home *** CD-ROM | disk | FTP | other *** search
/ Micromanía 92 / CDMM92_1.ISO / SOF 2 SDK / sof2sdk-101.msi / _92D6AC311BB48EBA344BBABC89DA6AB0 / _EEBCC5FAFFBF41A5B8E08DB9BFCC1879 < prev    next >
Encoding:
Text File  |  2002-07-02  |  182.4 KB  |  7,671 lines

  1. // Copyright (C) 2001-2002 Raven Software.
  2. // 
  3. // string allocation/managment
  4.  
  5. #include "ui_shared.h"
  6. #include "../game/bg_public.h"
  7.  
  8. #define SCROLL_TIME_START                    500
  9. #define SCROLL_TIME_ADJUST                150
  10. #define SCROLL_TIME_ADJUSTOFFSET    40
  11. #define SCROLL_TIME_FLOOR                    20
  12.  
  13. typedef struct scrollInfo_s {
  14.     int nextScrollTime;
  15.     int nextAdjustTime;
  16.     int adjustValue;
  17.     int scrollKey;
  18.     float xStart;
  19.     float yStart;
  20.     itemDef_t *item;
  21.     qboolean scrollDir;
  22. } scrollInfo_t;
  23.  
  24. static scrollInfo_t scrollInfo;
  25.  
  26. static void (*captureFunc) (void *p) = NULL;
  27. static void *captureData = NULL;
  28. static itemDef_t *itemCapture = NULL;        // item that has the mouse captured ( if any )
  29. static itemDef_t *itemExclusive = NULL;        // item that has exclusive input (combo box)
  30.  
  31. displayContextDef_t *DC = NULL;
  32.  
  33. static qboolean g_waitingForKey = qfalse;
  34. static qboolean g_editingField = qfalse;
  35.  
  36. static itemDef_t *g_bindItem = NULL;
  37. static itemDef_t *g_editItem = NULL;
  38.  
  39. menuDef_t Menus[MAX_MENUS];      // defined menus
  40. int menuCount = 0;               // how many
  41.  
  42. menuDef_t *menuStack[MAX_OPEN_MENUS];
  43. int openMenuCount = 0;
  44.  
  45. static qboolean debugMode = qfalse;
  46.  
  47. #define DOUBLE_CLICK_DELAY 300
  48. static int lastListBoxClickTime = 0;
  49.  
  50. void Item_RunScript(itemDef_t *item, const char *s);
  51. void Item_SetupKeywordHash(void);
  52. void Menu_SetupKeywordHash(void);
  53. int BindingIDFromName(const char *name);
  54. qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down);
  55. itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu);
  56. itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu);
  57. static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y);
  58. static void Item_TextScroll_BuildLines ( itemDef_t* item );
  59.  
  60. typedef struct  itemFlagsDef_s 
  61. {
  62.     char    *string;
  63.     int        value;
  64.  
  65. }    itemFlagsDef_t;
  66.  
  67. itemFlagsDef_t itemFlags [] = 
  68. {
  69.     "WINDOW_INACTIVE",        WINDOW_INACTIVE,
  70.     NULL,                    (int) NULL
  71. };
  72.  
  73. char *styles [] = 
  74. {
  75.     "WINDOW_STYLE_EMPTY",
  76.     "WINDOW_STYLE_FILLED",
  77.     "WINDOW_STYLE_SHADER",
  78.     "WINDOW_STYLE_CINEMATIC",
  79.     NULL
  80. };
  81.  
  82. char *alignment [] = 
  83. {
  84.     "ITEM_ALIGN_LEFT",
  85.     "ITEM_ALIGN_CENTER",
  86.     "ITEM_ALIGN_RIGHT",
  87.     NULL
  88. };
  89.  
  90. char *types [] = 
  91. {
  92.     "ITEM_TYPE_TEXT",
  93.     "ITEM_TYPE_BUTTON",
  94.     "ITEM_TYPE_RADIOBUTTON",
  95.     "ITEM_TYPE_CHECKBOX",
  96.     "ITEM_TYPE_EDITFIELD",
  97.     "ITEM_TYPE_COMBO",
  98.     "ITEM_TYPE_LISTBOX",
  99.     "ITEM_TYPE_OWNERDRAW",
  100.     "ITEM_TYPE_MODEL",
  101.     "ITEM_TYPE_NUMERICFIELD",
  102.     "ITEM_TYPE_SLIDER",
  103.     "ITEM_TYPE_YESNO",
  104.     "ITEM_TYPE_MULTI",
  105.     "ITEM_TYPE_BIND",
  106.     "ITEM_TYPE_PASSWORDFIELD",
  107.     "ITEM_TYPE_COMBOBOX",
  108.     "ITEM_TYPE_TEXTSCROLL",
  109.     NULL
  110. };
  111.  
  112. #if !(CGAME)
  113.     extern vmCvar_t    ui_allowparental;
  114. #endif
  115.  
  116. #define HASH_TABLE_SIZE 2048
  117.  
  118. /*
  119. ================
  120. return a hash value for the string
  121. ================
  122. */
  123. static long hashForString(const char *str) {
  124.     int        i;
  125.     long    hash;
  126.     char    letter;
  127.  
  128.     hash = 0;
  129.     i = 0;
  130.     while (str[i] != '\0') {
  131.         letter = tolower(str[i]);
  132.         hash+=(long)(letter)*(i+119);
  133.         i++;
  134.     }
  135.     hash &= (HASH_TABLE_SIZE-1);
  136.     return hash;
  137. }
  138.  
  139. typedef struct stringDef_s {
  140.     struct stringDef_s *next;
  141.     const char *str;
  142. } stringDef_t;
  143.  
  144. static int strPoolIndex = 0;
  145. static char strPool[STRING_POOL_SIZE];
  146.  
  147. static int strHandleCount = 0;
  148. static stringDef_t *strHandle[HASH_TABLE_SIZE];
  149.  
  150.  
  151. const char *String_Alloc(const char *p) {
  152.     int len;
  153.     long hash;
  154.     stringDef_t *str, *last;
  155.     static const char *staticNULL = "";
  156.  
  157.     if (p == NULL) {
  158.         return NULL;
  159.     }
  160.  
  161.     if (*p == 0) {
  162.         return staticNULL;
  163.     }
  164.  
  165.     hash = hashForString(p);
  166.  
  167.     str = strHandle[hash];
  168.     while (str) {
  169.         if (strcmp(p, str->str) == 0) {
  170.             return str->str;
  171.         }
  172.         str = str->next;
  173.     }
  174.  
  175.     len = strlen(p);
  176.     if (len + strPoolIndex + 1 < STRING_POOL_SIZE) {
  177.         int ph = strPoolIndex;
  178.         strcpy(&strPool[strPoolIndex], p);
  179.         strPoolIndex += len + 1;
  180.  
  181.         str = strHandle[hash];
  182.         last = str;
  183.         while (str && str->next) {
  184.             last = str;
  185.             str = str->next;
  186.         }
  187.  
  188.         str  = trap_VM_LocalAlloc(sizeof(stringDef_t));
  189.         str->next = NULL;
  190.         str->str = &strPool[ph];
  191.         if (last) {
  192.             last->next = str;
  193.         } else {
  194.             strHandle[hash] = str;
  195.         }
  196.         return &strPool[ph];
  197.     }
  198.     return NULL;
  199. }
  200.  
  201. void String_Report() {
  202.     float f;
  203.     Com_Printf("Memory/String Pool Info\n");
  204.     Com_Printf("----------------\n");
  205.     f = strPoolIndex;
  206.     f /= STRING_POOL_SIZE;
  207.     f *= 100;
  208.     Com_Printf("String Pool is %.1f%% full, %i bytes out of %i used.\n", f, strPoolIndex, STRING_POOL_SIZE);
  209. }
  210.  
  211. /*
  212. =================
  213. String_Init
  214. =================
  215. */
  216. void String_Init() {
  217.     int i;
  218.     for (i = 0; i < HASH_TABLE_SIZE; i++) {
  219.         strHandle[i] = 0;
  220.     }
  221.     strHandleCount = 0;
  222.     strPoolIndex = 0;
  223.     menuCount = 0;
  224.     openMenuCount = 0;
  225.     Item_SetupKeywordHash();
  226.     Menu_SetupKeywordHash();
  227.     if (DC && DC->getBindingBuf) {
  228.         Controls_GetConfig();
  229.     }
  230. }
  231.  
  232. /*
  233. =================
  234. PC_SourceWarning
  235. =================
  236. */
  237. void PC_SourceWarning(int handle, char *format, ...) 
  238. {
  239.     int line;
  240.     char filename[128];
  241.     va_list argptr;
  242.     static char string[4096];
  243.  
  244.     va_start (argptr, format);
  245.     vsprintf (string, format, argptr);
  246.     va_end (argptr);
  247.  
  248.     filename[0] = '\0';
  249.     line = 0;
  250.     trap_PC_SourceFileAndLine(handle, filename, &line);
  251.  
  252.     Com_Printf(S_COLOR_YELLOW "WARNING: %s, line %d: %s\n", filename, line, string);
  253. }
  254.  
  255. /*
  256. =================
  257. PC_SourceError
  258. =================
  259. */
  260. void PC_SourceError(int handle, char *format, ...) {
  261.     int line;
  262.     char filename[128];
  263.     va_list argptr;
  264.     static char string[4096];
  265.  
  266.     va_start (argptr, format);
  267.     vsprintf (string, format, argptr);
  268.     va_end (argptr);
  269.  
  270.     filename[0] = '\0';
  271.     line = 0;
  272.     trap_PC_SourceFileAndLine(handle, filename, &line);
  273.  
  274.     Com_Printf(S_COLOR_RED "ERROR: %s, line %d: %s\n", filename, line, string);
  275. }
  276.  
  277. /*
  278. =================
  279. LerpColor
  280. =================
  281. */
  282. void LerpColor(vec4_t a, vec4_t b, vec4_t c, float t)
  283. {
  284.     int i;
  285.  
  286.     // lerp and clamp each component
  287.     for (i=0; i<4; i++)
  288.     {
  289.         c[i] = a[i] + t*(b[i]-a[i]);
  290.         if (c[i] < 0)
  291.             c[i] = 0;
  292.         else if (c[i] > 1.0)
  293.             c[i] = 1.0;
  294.     }
  295. }
  296.  
  297. /*
  298. =================
  299. Float_Parse
  300. =================
  301. */
  302. qboolean Float_Parse(const char **p, float *f) {
  303.     char    *token;
  304.     token = COM_ParseExt(p, qfalse);
  305.     if (token && token[0] != 0) {
  306.         *f = atof(token);
  307.         return qtrue;
  308.     } else {
  309.         return qfalse;
  310.     }
  311. }
  312.  
  313. /*
  314. =================
  315. PC_Float_Parse
  316. =================
  317. */
  318. qboolean PC_Float_Parse(int handle, float *f) {
  319.     pc_token_t token;
  320.     int negative = qfalse;
  321.  
  322.     if (!trap_PC_ReadToken(handle, &token))
  323.         return qfalse;
  324.     if (token.string[0] == '-') {
  325.         if (!trap_PC_ReadToken(handle, &token))
  326.             return qfalse;
  327.         negative = qtrue;
  328.     }
  329.     if (token.type != TT_NUMBER) {
  330.         PC_SourceError(handle, "expected float but found %s\n", token.string);
  331.         return qfalse;
  332.     }
  333.     if (negative)
  334.         *f = -token.floatvalue;
  335.     else
  336.         *f = token.floatvalue;
  337.     return qtrue;
  338. }
  339.  
  340. /*
  341. =================
  342. Color_Parse
  343. =================
  344. */
  345. qboolean Color_Parse(const char **p, vec4_t *c) {
  346.     int i;
  347.     float f;
  348.  
  349.     for (i = 0; i < 4; i++) {
  350.         if (!Float_Parse(p, &f)) {
  351.             return qfalse;
  352.         }
  353.         (*c)[i] = f;
  354.     }
  355.     return qtrue;
  356. }
  357.  
  358. /*
  359. =================
  360. PC_Color_Parse
  361. =================
  362. */
  363. qboolean PC_Color_Parse(int handle, vec4_t *c) {
  364.     int i;
  365.     float f;
  366.  
  367.     for (i = 0; i < 4; i++) {
  368.         if (!PC_Float_Parse(handle, &f)) {
  369.             return qfalse;
  370.         }
  371.         (*c)[i] = f;
  372.     }
  373.     return qtrue;
  374. }
  375.  
  376. /*
  377. =================
  378. Int_Parse
  379. =================
  380. */
  381. qboolean Int_Parse(const char **p, int *i) {
  382.     char    *token;
  383.     token = COM_ParseExt(p, qfalse);
  384.  
  385.     if (token && token[0] != 0) {
  386.         *i = atoi(token);
  387.         return qtrue;
  388.     } else {
  389.         return qfalse;
  390.     }
  391. }
  392.  
  393. /*
  394. =================
  395. PC_Int_Parse
  396. =================
  397. */
  398. qboolean PC_Int_Parse(int handle, int *i) {
  399.     pc_token_t token;
  400.     int negative = qfalse;
  401.  
  402.     if (!trap_PC_ReadToken(handle, &token))
  403.         return qfalse;
  404.     if (token.string[0] == '-') {
  405.         if (!trap_PC_ReadToken(handle, &token))
  406.             return qfalse;
  407.         negative = qtrue;
  408.     }
  409.     if (token.type != TT_NUMBER) {
  410.         PC_SourceError(handle, "expected integer but found %s\n", token.string);
  411.         return qfalse;
  412.     }
  413.     *i = token.intvalue;
  414.     if (negative)
  415.         *i = - *i;
  416.     return qtrue;
  417. }
  418.  
  419. /*
  420. =================
  421. Rect_Parse
  422. =================
  423. */
  424. qboolean Rect_Parse(const char **p, rectDef_t *r) {
  425.     if (Float_Parse(p, &r->x)) {
  426.         if (Float_Parse(p, &r->y)) {
  427.             if (Float_Parse(p, &r->w)) {
  428.                 if (Float_Parse(p, &r->h)) {
  429.                     return qtrue;
  430.                 }
  431.             }
  432.         }
  433.     }
  434.     return qfalse;
  435. }
  436.  
  437. /*
  438. =================
  439. PC_Rect_Parse
  440. =================
  441. */
  442. qboolean PC_Rect_Parse(int handle, rectDef_t *r) {
  443.     if (PC_Float_Parse(handle, &r->x)) {
  444.         if (PC_Float_Parse(handle, &r->y)) {
  445.             if (PC_Float_Parse(handle, &r->w)) {
  446.                 if (PC_Float_Parse(handle, &r->h)) {
  447.                     return qtrue;
  448.                 }
  449.             }
  450.         }
  451.     }
  452.     return qfalse;
  453. }
  454.  
  455. /*
  456. =================
  457. String_Parse
  458. =================
  459. */
  460. qboolean String_Parse(const char **p, const char **out) {
  461.     char *token;
  462.  
  463.     token = COM_ParseExt(p, qfalse);
  464.     if (token && token[0] != 0) {
  465.         *(out) = String_Alloc(token);
  466.         return qtrue;
  467.     }
  468.     return qfalse;
  469. }
  470.  
  471. /*
  472. =================
  473. PC_String_Parse
  474. =================
  475. */
  476. qboolean PC_String_Parse(int handle, const char **out) 
  477. {
  478.     pc_token_t token;
  479.  
  480.     if (!trap_PC_ReadToken(handle, &token))
  481.     {
  482.         return qfalse;
  483.     }
  484.  
  485.     *(out) = String_Alloc(token.string);
  486.     return qtrue;
  487. }
  488.  
  489. /*
  490. =================
  491. PC_Script_Parse
  492. =================
  493. */
  494. qboolean PC_Script_Parse(int handle, const char **out) {
  495.     char script[1024];
  496.     pc_token_t token;
  497.  
  498.     memset(script, 0, sizeof(script));
  499.     // scripts start with { and have ; separated command lists.. commands are command, arg.. 
  500.     // basically we want everything between the { } as it will be interpreted at run time
  501.   
  502.     if (!trap_PC_ReadToken(handle, &token))
  503.         return qfalse;
  504.     if (Q_stricmp(token.string, "{") != 0) {
  505.         return qfalse;
  506.     }
  507.  
  508.     while ( 1 ) {
  509.         if (!trap_PC_ReadToken(handle, &token))
  510.             return qfalse;
  511.  
  512.         if (Q_stricmp(token.string, "}") == 0) {
  513.             *out = String_Alloc(script);
  514.             return qtrue;
  515.         }
  516.  
  517.         if (token.string[1] != '\0') {
  518.             Q_strcat(script, 1024, va("\"%s\"", token.string));
  519.         } else {
  520.             Q_strcat(script, 1024, token.string);
  521.         }
  522.         Q_strcat(script, 1024, " ");
  523.     }
  524.     return qfalse;     // bk001105 - LCC   missing return value
  525. }
  526.  
  527. /*
  528. ==================
  529. Init_Display
  530.  
  531. Initializes the display with a structure to all the drawing routines
  532.  ==================
  533. */
  534. void Init_Display(displayContextDef_t *dc) 
  535. {
  536.     DC = dc;
  537. }
  538.  
  539. /*
  540. ==================
  541. Window_Init
  542.  
  543. Initializes a window structure ( windowDef_t ) with defaults
  544. ==================
  545. */
  546. void Window_Init(Window *w) {
  547.     memset(w, 0, sizeof(windowDef_t));
  548.     w->borderSize = 1;
  549.     w->foreColor[0] = w->foreColor[1] = w->foreColor[2] = w->foreColor[3] = 1.0;
  550.     w->cinematic = -1;
  551. }
  552.  
  553. void Fade(int *flags, float *f, float clamp, int *nextTime, int offsetTime, qboolean bFlags, float fadeAmount) {
  554.   if (*flags & (WINDOW_FADINGOUT | WINDOW_FADINGIN)) {
  555.     if (DC->realTime > *nextTime) {
  556.       *nextTime = DC->realTime + offsetTime;
  557.       if (*flags & WINDOW_FADINGOUT) {
  558.         *f -= fadeAmount;
  559.         if (bFlags && *f <= 0.0) {
  560.           *flags &= ~(WINDOW_FADINGOUT | WINDOW_VISIBLE);
  561.         }
  562.       } else {
  563.         *f += fadeAmount;
  564.         if (*f >= clamp) {
  565.           *f = clamp;
  566.           if (bFlags) {
  567.             *flags &= ~WINDOW_FADINGIN;
  568.           }
  569.         }
  570.       }
  571.     }
  572.   }
  573. }
  574.  
  575.  
  576. void Item_SetMouseOver(itemDef_t *item, qboolean focus) {
  577.   if (item) {
  578.     if (focus) {
  579.       item->window.flags |= WINDOW_MOUSEOVER;
  580.     } else {
  581.       item->window.flags &= ~WINDOW_MOUSEOVER;
  582.     }
  583.   }
  584.  
  585.     // Save the item that the mouse is over
  586.     if ( item->tooltip )
  587.     {
  588.         if ( focus )
  589.         {
  590.             DC->tooltipItem = item;
  591.         }
  592.         else if ( DC->tooltipItem == item )
  593.         {
  594.             DC->tooltipItem = NULL;
  595.         }
  596.     }
  597. }
  598.  
  599. void Window_Paint(Window *w, float fadeAmount, float fadeClamp, float fadeCycle) 
  600. {
  601.     vec4_t        color;
  602.     rectDef_t    fillRect;
  603.  
  604.     fillRect = w->rect;
  605.  
  606.     if (debugMode) 
  607.     {
  608.         color[0] = color[1] = color[2] = color[3] = 1;
  609.         DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, 1, color);
  610.     }
  611.  
  612.     if (w == NULL || (w->style == 0 && w->border == 0)) 
  613.     {
  614.         return;
  615.     }
  616.  
  617.     if (w->border != 0) 
  618.     {
  619.         fillRect.x += w->borderSize;
  620.         fillRect.y += w->borderSize;
  621.         fillRect.w -= w->borderSize + 1;
  622.         fillRect.h -= w->borderSize + 1;
  623.     }
  624.  
  625.     if (w->style == WINDOW_STYLE_FILLED) 
  626.     {
  627.         // box, but possible a shader that needs filled
  628.         if (w->background) 
  629.         {
  630.             Fade(&w->flags, &w->backColor[3], fadeClamp, &w->nextTime, fadeCycle, qtrue, fadeAmount);
  631.             DC->setColor(w->backColor);
  632.             DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
  633.             DC->setColor(NULL);
  634.         } 
  635.         else 
  636.         {
  637.             DC->fillRect(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->backColor);
  638.         }
  639.     } 
  640.     else if (w->style == WINDOW_STYLE_SHADER) 
  641.     {
  642.         if (w->flags & WINDOW_FORECOLORSET) 
  643.         {
  644.             DC->setColor(w->foreColor);
  645.         }
  646.         DC->drawHandlePic(fillRect.x, fillRect.y, fillRect.w, fillRect.h, w->background);
  647.         DC->setColor(NULL);
  648.     } 
  649.     else if (w->style == WINDOW_STYLE_CINEMATIC) 
  650.     {
  651.         if (w->cinematic == -1) 
  652.         {
  653.             w->cinematic = DC->playCinematic(w->cinematicName, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
  654.             if (w->cinematic == -1) 
  655.             {
  656.                 w->cinematic = -2;
  657.             }
  658.         } 
  659.         if (w->cinematic >= 0) 
  660.         {
  661.             DC->runCinematicFrame(w->cinematic);
  662.             DC->drawCinematic(w->cinematic, fillRect.x, fillRect.y, fillRect.w, fillRect.h);
  663.         }
  664.     }
  665.  
  666.     if (w->border == WINDOW_BORDER_FULL) 
  667.     {
  668.         DC->drawRect(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize, w->borderColor);
  669.     } 
  670.     else if (w->border == WINDOW_BORDER_HORZ) 
  671.     {
  672.         // top/bottom
  673.         DC->setColor(w->borderColor);
  674.         DC->drawTopBottom(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
  675.         DC->setColor( NULL );
  676.     } 
  677.     else if (w->border == WINDOW_BORDER_VERT) 
  678.     {
  679.         // left right
  680.         DC->setColor(w->borderColor);
  681.         DC->drawSides(w->rect.x, w->rect.y, w->rect.w, w->rect.h, w->borderSize);
  682.         DC->setColor( NULL );
  683.     } 
  684. }
  685.  
  686.  
  687. void Item_SetScreenCoords(itemDef_t *item, float x, float y) 
  688.     if (item == NULL) 
  689.     {
  690.         return;
  691.     }
  692.  
  693.     if (item->window.border != 0) 
  694.     {
  695.         x += item->window.borderSize;
  696.         y += item->window.borderSize;
  697.     }
  698.  
  699.     item->window.rect.x = x + item->window.rectClient.x;
  700.     item->window.rect.y = y + item->window.rectClient.y;
  701.     item->window.rect.w = item->window.rectClient.w;
  702.     item->window.rect.h = item->window.rectClient.h;
  703.  
  704.     // force the text rects to recompute
  705.     item->textRect.w = 0;
  706.     item->textRect.h = 0;
  707.  
  708.     switch ( item->type )
  709.     {
  710.         case ITEM_TYPE_COMBOBOX:
  711.         {
  712.             listBoxDef_t* listPtr = (listBoxDef_t*) item->typeData;
  713.  
  714.             listPtr->comboRect = item->window.rect;
  715.             listPtr->comboRect.h = listPtr->elementHeight;
  716.  
  717.             if ( !(item->window.flags & WINDOW_DROPPED ) )
  718.             {
  719.                 item->window.rect.h = listPtr->elementHeight;
  720.             }
  721.  
  722.             listPtr->listRect = item->window.rect;
  723.             listPtr->listRect.y += (listPtr->elementHeight + item->window.border);
  724.             listPtr->listRect.h -= (listPtr->elementHeight + item->window.border);
  725.             
  726.             break;
  727.         }
  728.  
  729.         case ITEM_TYPE_LISTBOX:
  730.         {
  731.             listBoxDef_t* listPtr = (listBoxDef_t*) item->typeData;
  732.             listPtr->listRect = item->window.rect;
  733.             break;
  734.         }
  735.  
  736.         case ITEM_TYPE_TEXTSCROLL:
  737.         {
  738.             textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData;
  739.             if ( scrollPtr )
  740.             {
  741.                 scrollPtr->startPos = 0;
  742.                 scrollPtr->endPos = 0;
  743.             }
  744.  
  745.             Item_TextScroll_BuildLines ( item );
  746.  
  747.             break;
  748.         }
  749.     }    
  750. }
  751.  
  752. // FIXME: consolidate this with nearby stuff
  753. void Item_UpdatePosition(itemDef_t *item) 
  754. {
  755.     float x, y;
  756.     menuDef_t *menu;
  757.   
  758.     if (item == NULL || item->parent == NULL) 
  759.     {
  760.         return;
  761.     }
  762.  
  763.     menu = item->parent;
  764.  
  765.     x = menu->window.rect.x;
  766.     y = menu->window.rect.y;
  767.   
  768.     if (menu->window.border != 0) 
  769.     {
  770.         x += menu->window.borderSize;
  771.         y += menu->window.borderSize;
  772.     }
  773.  
  774.     Item_SetScreenCoords(item, x, y);
  775. }
  776.  
  777. // menus
  778. void Menu_UpdatePosition(menuDef_t *menu) 
  779. {
  780.     int      i;
  781.     float x;
  782.     float y;
  783.  
  784.     if (menu == NULL) 
  785.     {
  786.         return;
  787.     }
  788.   
  789.     x = menu->window.rect.x;
  790.     y = menu->window.rect.y;
  791.     
  792.     if (menu->window.border != 0) 
  793.     {
  794.         x += menu->window.borderSize;
  795.         y += menu->window.borderSize;
  796.     }
  797.  
  798.     for (i = 0; i < menu->itemCount; i++) 
  799.     {
  800.         Item_SetScreenCoords(menu->items[i], x, y);
  801.     }
  802. }
  803.  
  804. void Menu_PostParse(menuDef_t *menu) 
  805. {
  806.     if (menu == NULL) 
  807.     {
  808.         return;
  809.     }
  810.  
  811.     if (menu->fullScreen) 
  812.     {
  813.         menu->window.rect.x = 0;
  814.         menu->window.rect.y = 0;
  815.         menu->window.rect.w = 640;
  816.         menu->window.rect.h = 480;
  817.     }
  818.  
  819.     Menu_UpdatePosition(menu);
  820. }
  821.  
  822. itemDef_t *Menu_ClearFocus(menuDef_t *menu) {
  823.   int i;
  824.   itemDef_t *ret = NULL;
  825.  
  826.   if (menu == NULL) {
  827.     return NULL;
  828.   }
  829.  
  830.   for (i = 0; i < menu->itemCount; i++) {
  831.     if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
  832.       ret = menu->items[i];
  833.     } 
  834.     menu->items[i]->window.flags &= ~WINDOW_HASFOCUS;
  835.     if (menu->items[i]->leaveFocus) {
  836.       Item_RunScript(menu->items[i], menu->items[i]->leaveFocus);
  837.     }
  838.   }
  839.  
  840.   return ret;
  841. }
  842.  
  843. qboolean IsVisible(int flags) {
  844.   return (flags & WINDOW_VISIBLE && !(flags & WINDOW_FADINGOUT));
  845. }
  846.  
  847. qboolean Rect_ContainsPoint(rectDef_t *rect, float x, float y) {
  848.   if (rect) {
  849.     if (x > rect->x && x < rect->x + rect->w && y > rect->y && y < rect->y + rect->h) {
  850.       return qtrue;
  851.     }
  852.   }
  853.   return qfalse;
  854. }
  855.  
  856. int Menu_ItemsMatchingGroup(menuDef_t *menu, const char *name) {
  857.   int i;
  858.   int count = 0;
  859.   for (i = 0; i < menu->itemCount; i++) {
  860.     if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
  861.       count++;
  862.     } 
  863.   }
  864.   return count;
  865. }
  866.  
  867. itemDef_t *Menu_GetMatchingItemByNumber(menuDef_t *menu, int index, const char *name) {
  868.   int i;
  869.   int count = 0;
  870.   for (i = 0; i < menu->itemCount; i++) {
  871.     if (Q_stricmp(menu->items[i]->window.name, name) == 0 || (menu->items[i]->window.group && Q_stricmp(menu->items[i]->window.group, name) == 0)) {
  872.       if (count == index) {
  873.         return menu->items[i];
  874.       }
  875.       count++;
  876.     } 
  877.   }
  878.   return NULL;
  879. }
  880.  
  881.  
  882.  
  883. void Script_SetColor(itemDef_t *item, const char **args) {
  884.   const char *name;
  885.   int i;
  886.   float f;
  887.   vec4_t *out;
  888.   // expecting type of color to set and 4 args for the color
  889.   if (String_Parse(args, &name)) {
  890.       out = NULL;
  891.       if (Q_stricmp(name, "backcolor") == 0) {
  892.         out = &item->window.backColor;
  893.         item->window.flags |= WINDOW_BACKCOLORSET;
  894.       } else if (Q_stricmp(name, "forecolor") == 0) {
  895.         out = &item->window.foreColor;
  896.         item->window.flags |= WINDOW_FORECOLORSET;
  897.       } else if (Q_stricmp(name, "bordercolor") == 0) {
  898.         out = &item->window.borderColor;
  899.       }
  900.  
  901.       if (out) {
  902.         for (i = 0; i < 4; i++) {
  903.           if (!Float_Parse(args, &f)) {
  904.             return;
  905.           }
  906.           (*out)[i] = f;
  907.         }
  908.       }
  909.   }
  910. }
  911.  
  912. void Script_SetAsset(itemDef_t *item, const char **args) {
  913.   const char *name;
  914.   // expecting name to set asset to
  915.   if (String_Parse(args, &name)) {
  916.     // check for a model 
  917.     if (item->type == ITEM_TYPE_MODEL) {
  918.     }
  919.   }
  920. }
  921.  
  922. void Script_SetMenuBackground ( itemDef_t* item, const char **args)
  923. {
  924.     const char* name;
  925.  
  926.     // expecting name to set asset to
  927.     if (String_Parse(args, &name)) 
  928.     {
  929.         if ( item->parent )
  930.         {
  931.             menuDef_t* menu = (menuDef_t*)item->parent;
  932.             menu->window.background = DC->registerShaderNoMip(name);
  933.         }
  934.     }
  935. }
  936.  
  937.  
  938. void Script_SetBackground(itemDef_t *item, const char **args) 
  939. {
  940.     const char *name;
  941.  
  942.     // expecting name to set asset to
  943.     if (String_Parse(args, &name)) 
  944.     {
  945.         item->window.background = DC->registerShaderNoMip(name);
  946.     }
  947. }
  948.  
  949.  
  950.  
  951.  
  952. itemDef_t *Menu_FindItemByName(menuDef_t *menu, const char *p) {
  953.   int i;
  954.   if (menu == NULL || p == NULL) {
  955.     return NULL;
  956.   }
  957.  
  958.   for (i = 0; i < menu->itemCount; i++) {
  959.     if (Q_stricmp(p, menu->items[i]->window.name) == 0) {
  960.       return menu->items[i];
  961.     }
  962.   }
  963.  
  964.   return NULL;
  965. }
  966.  
  967. void Script_SetTeamColor(itemDef_t *item, const char **args) {
  968.   if (DC->getTeamColor) {
  969.     int i;
  970.     vec4_t color;
  971.     DC->getTeamColor(&color);
  972.     for (i = 0; i < 4; i++) {
  973.       item->window.backColor[i] = color[i];
  974.     }
  975.   }
  976. }
  977.  
  978. void Script_SetItemColor(itemDef_t *item, const char **args) {
  979.   const char *itemname;
  980.   const char *name;
  981.   vec4_t color;
  982.   int i;
  983.   vec4_t *out;
  984.   // expecting type of color to set and 4 args for the color
  985.   if (String_Parse(args, &itemname) && String_Parse(args, &name)) {
  986.     itemDef_t *item2;
  987.     int j;
  988.     int count = Menu_ItemsMatchingGroup(item->parent, itemname);
  989.  
  990.     if (!Color_Parse(args, &color)) {
  991.       return;
  992.     }
  993.  
  994.     for (j = 0; j < count; j++) {
  995.       item2 = Menu_GetMatchingItemByNumber(item->parent, j, itemname);
  996.       if (item2 != NULL) {
  997.         out = NULL;
  998.         if (Q_stricmp(name, "backcolor") == 0) {
  999.           out = &item2->window.backColor;
  1000.         } else if (Q_stricmp(name, "forecolor") == 0) {
  1001.           out = &item2->window.foreColor;
  1002.           item2->window.flags |= WINDOW_FORECOLORSET;
  1003.         } else if (Q_stricmp(name, "bordercolor") == 0) {
  1004.           out = &item2->window.borderColor;
  1005.         }
  1006.  
  1007.         if (out) {
  1008.           for (i = 0; i < 4; i++) {
  1009.             (*out)[i] = color[i];
  1010.           }
  1011.         }
  1012.       }
  1013.     }
  1014.   }
  1015. }
  1016.  
  1017.  
  1018. void Menu_ShowItemByName(menuDef_t *menu, const char *p, qboolean bShow) {
  1019.     itemDef_t *item;
  1020.     int i;
  1021.     int count = Menu_ItemsMatchingGroup(menu, p);
  1022.     for (i = 0; i < count; i++) {
  1023.         item = Menu_GetMatchingItemByNumber(menu, i, p);
  1024.         if (item != NULL) {
  1025.             if (bShow) {
  1026.                 item->window.flags |= WINDOW_VISIBLE;
  1027.             } else {
  1028.                 item->window.flags &= ~WINDOW_VISIBLE;
  1029.                 // stop cinematics playing in the window
  1030.                 if (item->window.cinematic >= 0) {
  1031.                     DC->stopCinematic(item->window.cinematic);
  1032.                     item->window.cinematic = -1;
  1033.                 }
  1034.  
  1035.                 if ( DC->tooltipItem == item )
  1036.                     DC->tooltipItem = NULL;
  1037.             }
  1038.         }
  1039.     }
  1040. }
  1041.  
  1042. void Menu_FadeItemByName(menuDef_t *menu, const char *p, qboolean fadeOut) {
  1043.   itemDef_t *item;
  1044.   int i;
  1045.   int count = Menu_ItemsMatchingGroup(menu, p);
  1046.   for (i = 0; i < count; i++) {
  1047.     item = Menu_GetMatchingItemByNumber(menu, i, p);
  1048.     if (item != NULL) {
  1049.       if (fadeOut) {
  1050.         item->window.flags |= (WINDOW_FADINGOUT | WINDOW_VISIBLE);
  1051.         item->window.flags &= ~WINDOW_FADINGIN;
  1052.       } else {
  1053.         item->window.flags |= (WINDOW_VISIBLE | WINDOW_FADINGIN);
  1054.         item->window.flags &= ~WINDOW_FADINGOUT;
  1055.       }
  1056.     }
  1057.   }
  1058. }
  1059.  
  1060. menuDef_t *Menus_FindByName(const char *p) {
  1061.   int i;
  1062.   for (i = 0; i < menuCount; i++) {
  1063.     if (Q_stricmp(Menus[i].window.name, p) == 0) {
  1064.       return &Menus[i];
  1065.     } 
  1066.   }
  1067.   return NULL;
  1068. }
  1069.  
  1070. void Menus_ShowByName(const char *p) {
  1071.     menuDef_t *menu = Menus_FindByName(p);
  1072.     if (menu) {
  1073.         Menus_Activate(menu);
  1074.     }
  1075. }
  1076.  
  1077. void Menus_OpenByName(const char *p) {
  1078.   Menus_ActivateByName(p);
  1079. }
  1080.  
  1081. static void Menu_RunCloseScript(menuDef_t *menu) {
  1082.     if (menu && (menu->window.flags & WINDOW_VISIBLE) && menu->onClose) {
  1083.         itemDef_t item;
  1084.     item.parent = menu;
  1085.     Item_RunScript(&item, menu->onClose);
  1086.     }
  1087. }
  1088.  
  1089. void Menus_CloseByName(const char *p) 
  1090. {
  1091.     menuDef_t *menu = Menus_FindByName(p);
  1092.     
  1093.     // If the menu wasnt found just exit
  1094.     if (menu == NULL) 
  1095.     {
  1096.         return;
  1097.     }
  1098.  
  1099.     // Run the close script for the menu
  1100.     Menu_RunCloseScript(menu);
  1101.  
  1102.     // If this window had the focus then take it away
  1103.     if ( menu->window.flags & WINDOW_HASFOCUS )
  1104.     {    
  1105.         // If there is something still in the open menu list then
  1106.         // set it to have focus now
  1107.         if ( openMenuCount )
  1108.         {
  1109.             // Subtract one from the open menu count to prepare to
  1110.             // remove the top menu from the list
  1111.             openMenuCount -= 1;
  1112.  
  1113.             // Set the top menu to have focus now
  1114.             menuStack[openMenuCount]->window.flags |= WINDOW_HASFOCUS;
  1115.  
  1116.             // Remove the top menu from the list
  1117.             menuStack[openMenuCount] = NULL;
  1118.         }
  1119.     }
  1120.  
  1121.     // Window is now invisible and doenst have focus
  1122.     menu->window.flags &= ~(WINDOW_VISIBLE | WINDOW_HASFOCUS);
  1123. }
  1124.  
  1125. void Menus_CloseAll() 
  1126. {
  1127.     int i;
  1128.  
  1129.     itemExclusive = NULL;
  1130.     itemCapture = NULL;
  1131.  
  1132.     g_waitingForKey = qfalse;
  1133.  
  1134.     for (i = 0; i < menuCount; i++) 
  1135.     {
  1136.         Menu_RunCloseScript ( &Menus[i] );
  1137.         Menus[i].window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
  1138.     }
  1139.  
  1140.     // Clear the menu stack
  1141.     openMenuCount = 0;
  1142. }
  1143.  
  1144. void Script_Show(itemDef_t *item, const char **args) {
  1145.   const char *name;
  1146.   if (String_Parse(args, &name)) {
  1147.     Menu_ShowItemByName(item->parent, name, qtrue);
  1148.   }
  1149. }
  1150.  
  1151. void Script_Hide(itemDef_t *item, const char **args) {
  1152.   const char *name;
  1153.   if (String_Parse(args, &name)) {
  1154.     Menu_ShowItemByName(item->parent, name, qfalse);
  1155.   }
  1156. }
  1157.  
  1158. void Script_FadeIn(itemDef_t *item, const char **args) {
  1159.   const char *name;
  1160.   if (String_Parse(args, &name)) {
  1161.     Menu_FadeItemByName(item->parent, name, qfalse);
  1162.   }
  1163. }
  1164.  
  1165. void Script_FadeOut(itemDef_t *item, const char **args) {
  1166.   const char *name;
  1167.   if (String_Parse(args, &name)) {
  1168.     Menu_FadeItemByName(item->parent, name, qtrue);
  1169.   }
  1170. }
  1171.  
  1172.  
  1173.  
  1174. void Script_Open(itemDef_t *item, const char **args) {
  1175.   const char *name;
  1176.   if (String_Parse(args, &name)) {
  1177.     Menus_OpenByName(name);
  1178.   }
  1179. }
  1180.  
  1181. void Script_Close(itemDef_t *item, const char **args) {
  1182.   const char *name;
  1183.   if (String_Parse(args, &name)) {
  1184.     Menus_CloseByName(name);
  1185.   }
  1186. }
  1187.  
  1188. void Menu_TransitionItemByName(menuDef_t *menu, const char *p, rectDef_t rectFrom, rectDef_t rectTo, int time, float amt) {
  1189.   itemDef_t *item;
  1190.   int i;
  1191.   int count = Menu_ItemsMatchingGroup(menu, p);
  1192.   for (i = 0; i < count; i++) {
  1193.     item = Menu_GetMatchingItemByNumber(menu, i, p);
  1194.     if (item != NULL) {
  1195.       item->window.flags |= (WINDOW_INTRANSITION | WINDOW_VISIBLE);
  1196.       item->window.offsetTime = time;
  1197.             memcpy(&item->window.rectClient, &rectFrom, sizeof(rectDef_t));
  1198.             memcpy(&item->window.rectEffects, &rectTo, sizeof(rectDef_t));
  1199.             item->window.rectEffects2.x = abs(rectTo.x - rectFrom.x) / amt;
  1200.             item->window.rectEffects2.y = abs(rectTo.y - rectFrom.y) / amt;
  1201.             item->window.rectEffects2.w = abs(rectTo.w - rectFrom.w) / amt;
  1202.             item->window.rectEffects2.h = abs(rectTo.h - rectFrom.h) / amt;
  1203.       Item_UpdatePosition(item);
  1204.     }
  1205.   }
  1206. }
  1207.  
  1208.  
  1209. void Script_Transition(itemDef_t *item, const char **args) {
  1210.   const char *name;
  1211.     rectDef_t rectFrom, rectTo;
  1212.   int time;
  1213.     float amt;
  1214.  
  1215.   if (String_Parse(args, &name)) {
  1216.     if ( Rect_Parse(args, &rectFrom) && Rect_Parse(args, &rectTo) && Int_Parse(args, &time) && Float_Parse(args, &amt)) {
  1217.       Menu_TransitionItemByName(item->parent, name, rectFrom, rectTo, time, amt);
  1218.     }
  1219.   }
  1220. }
  1221.  
  1222.  
  1223. void Menu_OrbitItemByName(menuDef_t *menu, const char *p, float x, float y, float cx, float cy, int time) {
  1224.   itemDef_t *item;
  1225.   int i;
  1226.   int count = Menu_ItemsMatchingGroup(menu, p);
  1227.   for (i = 0; i < count; i++) {
  1228.     item = Menu_GetMatchingItemByNumber(menu, i, p);
  1229.     if (item != NULL) {
  1230.       item->window.flags |= (WINDOW_ORBITING | WINDOW_VISIBLE);
  1231.       item->window.offsetTime = time;
  1232.       item->window.rectEffects.x = cx;
  1233.       item->window.rectEffects.y = cy;
  1234.       item->window.rectClient.x = x;
  1235.       item->window.rectClient.y = y;
  1236.       Item_UpdatePosition(item);
  1237.     }
  1238.   }
  1239. }
  1240.  
  1241.  
  1242. void Script_Orbit(itemDef_t *item, const char **args) {
  1243.   const char *name;
  1244.   float cx, cy, x, y;
  1245.   int time;
  1246.  
  1247.   if (String_Parse(args, &name)) {
  1248.     if ( Float_Parse(args, &x) && Float_Parse(args, &y) && Float_Parse(args, &cx) && Float_Parse(args, &cy) && Int_Parse(args, &time) ) {
  1249.       Menu_OrbitItemByName(item->parent, name, x, y, cx, cy, time);
  1250.     }
  1251.   }
  1252. }
  1253.  
  1254.  
  1255.  
  1256. void Script_SetFocus(itemDef_t *item, const char **args) 
  1257. {
  1258.     const char    *name;
  1259.     itemDef_t    *focusItem;
  1260.  
  1261.     if (String_Parse(args, &name)) 
  1262.     {
  1263.         focusItem = Menu_FindItemByName(item->parent, name);
  1264.         if (focusItem && !(focusItem->window.flags & WINDOW_DECORATION) && !(focusItem->window.flags & WINDOW_HASFOCUS)) 
  1265.         {
  1266.             Menu_ClearFocus(item->parent);
  1267.             focusItem->window.flags |= WINDOW_HASFOCUS;
  1268.  
  1269.             if ( focusItem->type == ITEM_TYPE_EDITFIELD ||
  1270.                  focusItem->type == ITEM_TYPE_PASSWORDFIELD )
  1271.             {
  1272.                 focusItem->cursorPos = 0;
  1273.                 g_editingField = qtrue;
  1274.                 g_editItem = focusItem;
  1275.                 DC->setOverstrikeMode(qtrue);
  1276.             }
  1277.  
  1278.             if (focusItem->onFocus) 
  1279.             {
  1280.                 Item_RunScript(focusItem, focusItem->onFocus);
  1281.             }
  1282.             
  1283.             if (DC->Assets.itemFocusSound) 
  1284.             {
  1285.                 DC->startLocalSound( DC->Assets.itemFocusSound, CHAN_LOCAL_SOUND );
  1286.             }
  1287.         }
  1288.     }
  1289. }
  1290.  
  1291. void Script_SetPlayerModel(itemDef_t *item, const char **args) {
  1292.   const char *name;
  1293.   if (String_Parse(args, &name)) {
  1294.     DC->setCVar("team_model", name);
  1295.   }
  1296. }
  1297.  
  1298. void Script_SetPlayerSkin(itemDef_t *item, const char **args) {
  1299.   const char *name;
  1300.   if (String_Parse(args, &name)) {
  1301.     DC->setCVar("team_skin", name);
  1302.   }
  1303. }
  1304.  
  1305. void Script_SetCvar(itemDef_t *item, const char **args) {
  1306.     const char *cvar, *val;
  1307.     if (String_Parse(args, &cvar) && String_Parse(args, &val)) {
  1308.         DC->setCVar(cvar, val);
  1309.     }
  1310.     
  1311. }
  1312.  
  1313. void Script_Exec(itemDef_t *item, const char **args) {
  1314.     const char *val;
  1315.     if (String_Parse(args, &val)) {
  1316.         DC->executeText(EXEC_APPEND, va("%s ; ", val));
  1317.     }
  1318. }
  1319.  
  1320. void Script_Play(itemDef_t *item, const char **args) {
  1321.     const char *val;
  1322.     if (String_Parse(args, &val)) {
  1323.         DC->startLocalSound(DC->registerSound(val), CHAN_LOCAL_SOUND);
  1324.     }
  1325. }
  1326.  
  1327. void Script_playLooped(itemDef_t *item, const char **args) {
  1328.     const char *val;
  1329.     if (String_Parse(args, &val)) {
  1330.         DC->stopBackgroundTrack();
  1331.         DC->startBackgroundTrack(val, val, qfalse);
  1332.     }
  1333. }
  1334.  
  1335.  
  1336. commandDef_t commandList[] =
  1337. {
  1338.   {"fadein", &Script_FadeIn},                   // group/name
  1339.   {"fadeout", &Script_FadeOut},                 // group/name
  1340.   {"show", &Script_Show},                       // group/name
  1341.   {"hide", &Script_Hide},                       // group/name
  1342.   {"setcolor", &Script_SetColor},               // works on this
  1343.   {"open", &Script_Open},                       // nenu
  1344.   {"close", &Script_Close},                     // menu
  1345.   {"setmenubackground", &Script_SetMenuBackground },    //menu
  1346.   {"setasset", &Script_SetAsset},               // works on this
  1347.   {"setbackground", &Script_SetBackground},     // works on this
  1348.   {"setitemcolor", &Script_SetItemColor},       // group/name
  1349.   {"setteamcolor", &Script_SetTeamColor},       // sets this background color to team color
  1350.   {"setfocus", &Script_SetFocus},               // sets this background color to team color
  1351.   {"setplayermodel", &Script_SetPlayerModel},   // sets this background color to team color
  1352.   {"setplayerskin", &Script_SetPlayerSkin},     // sets this background color to team color
  1353.   {"transition", &Script_Transition},           // group/name
  1354.   {"setcvar", &Script_SetCvar},                    // group/name
  1355.   {"exec", &Script_Exec},                        // group/name
  1356.   {"play", &Script_Play},                        // group/name
  1357.   {"playlooped", &Script_playLooped},           // group/name
  1358.   {"orbit", &Script_Orbit}                      // group/name
  1359. };
  1360.  
  1361. int scriptCommandCount = sizeof(commandList) / sizeof(commandDef_t);
  1362.  
  1363.  
  1364. void Item_RunScript(itemDef_t *item, const char *s) {
  1365.   char script[1024];
  1366.   const char *p;
  1367.   int i;
  1368.   qboolean bRan;
  1369.   memset(script, 0, sizeof(script));
  1370.   if (item && s && s[0]) {
  1371.     Q_strcat(script, 1024, s);
  1372.     p = script;
  1373.     while (1) {
  1374.       const char *command;
  1375.       // expect command then arguments, ; ends command, NULL ends script
  1376.       if (!String_Parse(&p, &command)) {
  1377.         return;
  1378.       }
  1379.  
  1380.       if (command[0] == ';' && command[1] == '\0') {
  1381.         continue;
  1382.       }
  1383.  
  1384.       bRan = qfalse;
  1385.       for (i = 0; i < scriptCommandCount; i++) {
  1386.         if (Q_stricmp(command, commandList[i].name) == 0) {
  1387.           (commandList[i].handler(item, &p));
  1388.           bRan = qtrue;
  1389.           break;
  1390.         }
  1391.       }
  1392.       // not in our auto list, pass to handler
  1393.       if (!bRan) {
  1394.         DC->runScript(&p);
  1395.       }
  1396.     }
  1397.   }
  1398. }
  1399.  
  1400.  
  1401. qboolean Item_EnableShowViaCvar(itemDef_t *item, int flag) 
  1402. {
  1403.     char        script[1024];
  1404.     const char    *p;
  1405.   
  1406.     memset(script, 0, sizeof(script));
  1407.  
  1408.     if (item && item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) 
  1409.     {
  1410.         char buff[1024];
  1411.     
  1412.         DC->getCVarString(item->cvarTest, buff, sizeof(buff));
  1413.  
  1414.         Q_strcat(script, 1024, item->enableCvar);
  1415.         
  1416.         p = script;
  1417.         
  1418.         while (1) 
  1419.         {
  1420.             const char *val;
  1421.       
  1422.             // expect value then ; or NULL, NULL ends list
  1423.             if (!String_Parse(&p, &val)) 
  1424.             {
  1425.                 return (item->cvarFlags & flag) ? qfalse : qtrue;
  1426.             }
  1427.  
  1428.             if (val[0] == ';' && val[1] == '\0') 
  1429.             {
  1430.                 continue;
  1431.             }
  1432.  
  1433.             // enable it if any of the values are true
  1434.             if (item->cvarFlags & flag) 
  1435.             {
  1436.                 if (Q_stricmp(buff, val) == 0) 
  1437.                 {
  1438.                     return qtrue;
  1439.                 }
  1440.             } 
  1441.             else 
  1442.             {
  1443.                 // disable it if any of the values are true
  1444.                 if (Q_stricmp(buff, val) == 0) 
  1445.                 {
  1446.                     return qfalse;
  1447.                 }
  1448.             }
  1449.         }
  1450.  
  1451.         return (item->cvarFlags & flag) ? qfalse : qtrue;
  1452.     }
  1453.     
  1454.     return qtrue;
  1455. }
  1456.  
  1457.  
  1458. // will optionaly set focus to this item 
  1459. qboolean Item_SetFocus(itemDef_t *item, float x, float y) 
  1460. {
  1461.     int i;
  1462.     itemDef_t *oldFocus;
  1463.     sfxHandle_t *sfx = &DC->Assets.itemFocusSound;
  1464.     qboolean playSound = qfalse;
  1465.     menuDef_t *parent; // bk001206: = (menuDef_t*)item->parent;
  1466.  
  1467.     // sanity check, non-null, not a decoration and does not already have the focus
  1468.     if (item == NULL || item->window.flags & WINDOW_DECORATION || item->window.flags & WINDOW_HASFOCUS || !(item->window.flags & WINDOW_VISIBLE) || (item->window.flags & WINDOW_DISABLED)) 
  1469.     {
  1470.         return qfalse;
  1471.     }
  1472.  
  1473.     // bk001206 - this can be NULL.
  1474.     parent = (menuDef_t*)item->parent; 
  1475.       
  1476.     // items can be enabled and disabled based on cvars
  1477.     if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) {
  1478.         return qfalse;
  1479.     }
  1480.  
  1481.     if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) {
  1482.         return qfalse;
  1483.     }
  1484.  
  1485.     oldFocus = Menu_ClearFocus(item->parent);
  1486.  
  1487.     if (item->type == ITEM_TYPE_TEXT) {
  1488.         rectDef_t r;
  1489.         r = item->textRect;
  1490.         r.y -= r.h;
  1491.         if (Rect_ContainsPoint(&r, x, y)) {
  1492.             item->window.flags |= WINDOW_HASFOCUS;
  1493.             if (item->focusSound) {
  1494.                 sfx = &item->focusSound;
  1495.             }
  1496.             playSound = qtrue;
  1497.         } else {
  1498.             if (oldFocus) {
  1499.                 oldFocus->window.flags |= WINDOW_HASFOCUS;
  1500.                 if (oldFocus->onFocus) {
  1501.                     Item_RunScript(oldFocus, oldFocus->onFocus);
  1502.                 }
  1503.             }
  1504.         }
  1505.     } else {
  1506.         item->window.flags |= WINDOW_HASFOCUS;
  1507.         if (item->onFocus) {
  1508.             Item_RunScript(item, item->onFocus);
  1509.         }
  1510.         if (item->focusSound) {
  1511.             sfx = &item->focusSound;
  1512.         }
  1513.         playSound = qtrue;
  1514.     }
  1515.  
  1516.     if (playSound && sfx) {
  1517.         DC->startLocalSound( *sfx, CHAN_AUTO );
  1518.     }
  1519.  
  1520.     for (i = 0; i < parent->itemCount; i++) {
  1521.         if (parent->items[i] == item) {
  1522.             parent->cursorItem = i;
  1523.             break;
  1524.         }
  1525.     }
  1526.  
  1527.     return qtrue;
  1528. }
  1529.  
  1530. int Item_TextScroll_MaxScroll ( itemDef_t *item ) 
  1531. {
  1532.     textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData;
  1533.     
  1534.     int count = scrollPtr->lineCount;
  1535.     int max   = count - (int)(item->window.rect.h / scrollPtr->lineHeight) + 1;
  1536.  
  1537.     if (max < 0) 
  1538.     {
  1539.         return 0;
  1540.     }
  1541.  
  1542.     return max;
  1543. }
  1544.  
  1545. int Item_TextScroll_ThumbPosition ( itemDef_t *item ) 
  1546. {
  1547.     float max, pos, size;
  1548.     textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData;
  1549.  
  1550.     max  = Item_TextScroll_MaxScroll ( item );
  1551.     size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2;
  1552.  
  1553.     if (max > 0) 
  1554.     {
  1555.         pos = (size-SCROLLBAR_SIZE) / (float) max;
  1556.     } 
  1557.     else 
  1558.     {
  1559.         pos = 0;
  1560.     }
  1561.     
  1562.     pos *= scrollPtr->startPos;
  1563.     
  1564.     return item->window.rect.y + 1 + SCROLLBAR_SIZE + pos;
  1565. }
  1566.  
  1567. int Item_TextScroll_ThumbDrawPosition ( itemDef_t *item ) 
  1568. {
  1569.     int min, max;
  1570.  
  1571.     if (itemCapture == item) 
  1572.     {
  1573.         min = item->window.rect.y + SCROLLBAR_SIZE + 1;
  1574.         max = item->window.rect.y + item->window.rect.h - 2*SCROLLBAR_SIZE - 1;
  1575.  
  1576.         if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) 
  1577.         {
  1578.             return DC->cursory - SCROLLBAR_SIZE/2;
  1579.         }
  1580.  
  1581.         return Item_TextScroll_ThumbPosition(item);
  1582.     }
  1583.  
  1584.     return Item_TextScroll_ThumbPosition(item);
  1585. }
  1586.  
  1587. int Item_TextScroll_OverLB ( itemDef_t *item, float x, float y ) 
  1588. {
  1589.     rectDef_t        r;
  1590.     textScrollDef_t *scrollPtr;
  1591.     int                thumbstart;
  1592.     int                count;
  1593.  
  1594.     scrollPtr = (textScrollDef_t*)item->typeData;
  1595.     count     = scrollPtr->lineCount;
  1596.  
  1597.     r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE;
  1598.     r.y = item->window.rect.y;
  1599.     r.h = r.w = SCROLLBAR_SIZE;
  1600.     if (Rect_ContainsPoint(&r, x, y)) 
  1601.     {
  1602.         return WINDOW_LB_LEFTARROW;
  1603.     }
  1604.  
  1605.     r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
  1606.     if (Rect_ContainsPoint(&r, x, y)) 
  1607.     {
  1608.         return WINDOW_LB_RIGHTARROW;
  1609.     }
  1610.  
  1611.     thumbstart = Item_TextScroll_ThumbPosition(item);
  1612.     r.y = thumbstart;
  1613.     if (Rect_ContainsPoint(&r, x, y)) 
  1614.     {
  1615.         return WINDOW_LB_THUMB;
  1616.     }
  1617.  
  1618.     r.y = item->window.rect.y + SCROLLBAR_SIZE;
  1619.     r.h = thumbstart - r.y;
  1620.     if (Rect_ContainsPoint(&r, x, y)) 
  1621.     {
  1622.         return WINDOW_LB_PGUP;
  1623.     }
  1624.  
  1625.     r.y = thumbstart + SCROLLBAR_SIZE;
  1626.     r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_SIZE;
  1627.     if (Rect_ContainsPoint(&r, x, y)) 
  1628.     {
  1629.         return WINDOW_LB_PGDN;
  1630.     }
  1631.  
  1632.     return 0;
  1633. }
  1634.  
  1635. void Item_TextScroll_MouseEnter (itemDef_t *item, float x, float y) 
  1636. {
  1637.     item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN);
  1638.     item->window.flags |= Item_TextScroll_OverLB(item, x, y);
  1639. }
  1640.  
  1641. qboolean Item_TextScroll_HandleKey ( itemDef_t *item, int key, qboolean down, qboolean force) 
  1642. {
  1643.     textScrollDef_t *scrollPtr = (textScrollDef_t*)item->typeData;
  1644.     int                max;
  1645.     int                viewmax;
  1646.  
  1647.     if (force || (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS)) 
  1648.     {
  1649.         max = Item_TextScroll_MaxScroll(item);
  1650.  
  1651.         viewmax = (item->window.rect.h / scrollPtr->lineHeight);
  1652.         if ( key == K_UPARROW || key == K_KP_UPARROW ) 
  1653.         {
  1654.             scrollPtr->startPos--;
  1655.             if (scrollPtr->startPos < 0)
  1656.             {
  1657.                 scrollPtr->startPos = 0;
  1658.             }
  1659.             return qtrue;
  1660.         }
  1661.  
  1662.         if ( key == K_DOWNARROW || key == K_KP_DOWNARROW ) 
  1663.         {
  1664.             scrollPtr->startPos++;
  1665.             if (scrollPtr->startPos > max)
  1666.             {
  1667.                 scrollPtr->startPos = max;
  1668.             }
  1669.  
  1670.             return qtrue;
  1671.         }
  1672.  
  1673.         // mouse hit
  1674.         if (key == K_MOUSE1 || key == K_MOUSE2) 
  1675.         {
  1676.             if (item->window.flags & WINDOW_LB_LEFTARROW) 
  1677.             {
  1678.                 scrollPtr->startPos--;
  1679.                 if (scrollPtr->startPos < 0) 
  1680.                 {
  1681.                     scrollPtr->startPos = 0;
  1682.                 }
  1683.             } 
  1684.             else if (item->window.flags & WINDOW_LB_RIGHTARROW) 
  1685.             {
  1686.                 // one down
  1687.                 scrollPtr->startPos++;
  1688.                 if (scrollPtr->startPos > max) 
  1689.                 {
  1690.                     scrollPtr->startPos = max;
  1691.                 }
  1692.             } 
  1693.             else if (item->window.flags & WINDOW_LB_PGUP) 
  1694.             {
  1695.                 // page up
  1696.                 scrollPtr->startPos -= viewmax;
  1697.                 if (scrollPtr->startPos < 0) 
  1698.                 {
  1699.                     scrollPtr->startPos = 0;
  1700.                 }
  1701.             } 
  1702.             else if (item->window.flags & WINDOW_LB_PGDN) 
  1703.             {
  1704.                 // page down
  1705.                 scrollPtr->startPos += viewmax;
  1706.                 if (scrollPtr->startPos > max) 
  1707.                 {
  1708.                     scrollPtr->startPos = max;
  1709.                 }
  1710.             } 
  1711.             else if (item->window.flags & WINDOW_LB_THUMB) 
  1712.             {
  1713.                 // Display_SetCaptureItem(item);
  1714.             } 
  1715.  
  1716.             return qtrue;
  1717.         }
  1718.  
  1719.         if ( key == K_HOME || key == K_KP_HOME) 
  1720.         {
  1721.             // home
  1722.             scrollPtr->startPos = 0;
  1723.             return qtrue;
  1724.         }
  1725.         if ( key == K_END || key == K_KP_END) 
  1726.         {
  1727.             // end
  1728.             scrollPtr->startPos = max;
  1729.             return qtrue;
  1730.         }
  1731.         if (key == K_PGUP || key == K_KP_PGUP ) 
  1732.         {
  1733.             scrollPtr->startPos -= viewmax;
  1734.             if (scrollPtr->startPos < 0) 
  1735.             {
  1736.                     scrollPtr->startPos = 0;
  1737.             }
  1738.  
  1739.             return qtrue;
  1740.         }
  1741.         if ( key == K_PGDN || key == K_KP_PGDN ) 
  1742.         {
  1743.             scrollPtr->startPos += viewmax;
  1744.             if (scrollPtr->startPos > max) 
  1745.             {
  1746.                 scrollPtr->startPos = max;
  1747.             }
  1748.             return qtrue;
  1749.         }
  1750.     }
  1751.  
  1752.     return qfalse;
  1753. }
  1754.  
  1755. int Item_ListBox_MaxScroll(itemDef_t *item) {
  1756.     listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  1757.     int count = DC->feederCount(item->special);
  1758.     int max;
  1759.  
  1760.     if (item->window.flags & WINDOW_HORIZONTAL) 
  1761.     {
  1762.         max = count - (item->window.rect.w / listPtr->elementWidth) + 1;
  1763.     }
  1764.     else 
  1765.     {
  1766.         float h;
  1767.  
  1768.         h = item->window.rect.h;
  1769.         if ( item->type == ITEM_TYPE_COMBOBOX  )
  1770.         {
  1771.             h -= (item->window.border + listPtr->elementHeight);
  1772.         }
  1773.  
  1774.         max = count - (h / listPtr->elementHeight) + 1;
  1775.     }
  1776.  
  1777.     if (max < 0) 
  1778.     {
  1779.         return 0;
  1780.     }
  1781.  
  1782.     return max;
  1783. }
  1784.  
  1785. int Item_ListBox_ThumbPosition(itemDef_t *item) 
  1786. {
  1787.     float         max;
  1788.     float         pos;
  1789.     float         size;
  1790.     listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  1791.  
  1792.     max = Item_ListBox_MaxScroll(item);
  1793.  
  1794.     if (item->window.flags & WINDOW_HORIZONTAL) 
  1795.     {
  1796.         size = item->window.rect.w - (SCROLLBAR_SIZE * 2) - 2;
  1797.         if (max > 0) 
  1798.         {
  1799.             pos = (size-SCROLLBAR_SIZE) / (float) max;
  1800.         } 
  1801.         else 
  1802.         {
  1803.             pos = 0;
  1804.         }
  1805.         
  1806.         pos *= listPtr->startPos;
  1807.         
  1808.         return item->window.rect.x + 1 + SCROLLBAR_SIZE + pos;
  1809.     }
  1810.     else 
  1811.     {
  1812.         float y;
  1813.  
  1814.         size = item->window.rect.h - (SCROLLBAR_SIZE * 2) - 2;
  1815.     
  1816.         if (max > 0) 
  1817.         {
  1818.             pos = (size-SCROLLBAR_SIZE) / (float) max;
  1819.         } 
  1820.         else 
  1821.         {
  1822.             pos = 0;
  1823.         }
  1824.         
  1825.         y = item->window.rect.y;
  1826.         if ( item->type == ITEM_TYPE_COMBOBOX  )
  1827.         {
  1828.             y += (item->window.border + listPtr->elementHeight);
  1829.         }
  1830.  
  1831.         pos *= listPtr->startPos;
  1832.         return y + 1 + SCROLLBAR_SIZE + pos;
  1833.     }
  1834. }
  1835.  
  1836. int Item_ListBox_ThumbDrawPosition(itemDef_t *item) 
  1837. {
  1838.     int min, max;
  1839.     listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  1840.  
  1841.     if (itemCapture == item) 
  1842.     {
  1843.         if (item->window.flags & WINDOW_HORIZONTAL) 
  1844.         {
  1845.             min = item->window.rect.x + SCROLLBAR_SIZE + 1;
  1846.             max = item->window.rect.x + item->window.rect.w - 2*SCROLLBAR_SIZE - 1;
  1847.             if (DC->cursorx >= min + SCROLLBAR_SIZE/2 && DC->cursorx <= max + SCROLLBAR_SIZE/2) 
  1848.             {
  1849.                 return DC->cursorx - SCROLLBAR_SIZE/2;
  1850.             }
  1851.  
  1852.             return Item_ListBox_ThumbPosition(item);
  1853.         }
  1854.         else 
  1855.         {
  1856.             float y;
  1857.             float h;
  1858.  
  1859.             y = item->window.rect.y;
  1860.             h = item->window.rect.h;
  1861.             if ( item->type == ITEM_TYPE_COMBOBOX  )
  1862.             {
  1863.                 y += (item->window.border + listPtr->elementHeight);
  1864.                 h -= (item->window.border + listPtr->elementHeight);
  1865.             }
  1866.  
  1867.             min = y + SCROLLBAR_SIZE + 1;
  1868.             max = y + h - 2 * SCROLLBAR_SIZE - 1;
  1869.             if (DC->cursory >= min + SCROLLBAR_SIZE/2 && DC->cursory <= max + SCROLLBAR_SIZE/2) 
  1870.             {
  1871.                 return DC->cursory - SCROLLBAR_SIZE/2;
  1872.             }
  1873.  
  1874.             return Item_ListBox_ThumbPosition(item);
  1875.         }
  1876.     }
  1877.  
  1878.     return Item_ListBox_ThumbPosition(item);
  1879. }
  1880.  
  1881. float Item_Slider_ThumbPosition ( itemDef_t *item ) 
  1882. {
  1883.     float            value;
  1884.     float            range;
  1885.     float            x;
  1886.     editFieldDef_t    *editDef = item->typeData;
  1887.  
  1888.     if (item->text && *item->text) 
  1889.     {
  1890.         x = item->textRect.x + item->textRect.w + 8;
  1891.     } 
  1892.     else 
  1893.     {
  1894.         x = item->window.rect.x; //  + (SLIDER_THUMB_WIDTH/2);
  1895.     }
  1896.  
  1897.     if (editDef == NULL && item->cvar) 
  1898.     {
  1899.         return x;
  1900.     }
  1901.  
  1902.     value = DC->getCVarValue(item->cvar);
  1903.  
  1904.     if (value < editDef->minVal) 
  1905.     {
  1906.         value = editDef->minVal;
  1907.     } 
  1908.     else if (value > editDef->maxVal) 
  1909.     {
  1910.         value = editDef->maxVal;
  1911.     }
  1912.  
  1913.     range = editDef->maxVal - editDef->minVal;
  1914.     value -= editDef->minVal;
  1915.     value /= range;
  1916.     value *= (SLIDER_WIDTH - SLIDER_THUMB_WIDTH);
  1917.     x += value;
  1918.  
  1919.     return x;
  1920. }
  1921.  
  1922. int Item_Slider_OverSlider(itemDef_t *item, float x, float y) 
  1923. {
  1924.     rectDef_t r;
  1925.  
  1926.     r.x = Item_Slider_ThumbPosition(item);
  1927.     r.y = item->window.rect.y;
  1928.     r.w = SLIDER_THUMB_WIDTH;
  1929.     r.h = SLIDER_THUMB_HEIGHT;
  1930.  
  1931.     if (Rect_ContainsPoint(&r, x, y)) 
  1932.     {
  1933.         return WINDOW_LB_THUMB;
  1934.     }
  1935.  
  1936.     return 0;
  1937. }
  1938.  
  1939. int Item_ListBox_OverLB(itemDef_t *item, float x, float y) 
  1940. {
  1941.     rectDef_t        r;
  1942.     listBoxDef_t    *listPtr;
  1943.     int                thumbstart;
  1944.     int                count;
  1945.  
  1946.     count = DC->feederCount(item->special);
  1947.     listPtr = (listBoxDef_t*)item->typeData;
  1948.  
  1949.     if (item->window.flags & WINDOW_HORIZONTAL) {
  1950.         // check if on left arrow
  1951.         r.x = listPtr->listRect.x;
  1952.         r.y = listPtr->listRect.y + listPtr->listRect.h - SCROLLBAR_SIZE;
  1953.         r.h = r.w = SCROLLBAR_SIZE;
  1954.         if (Rect_ContainsPoint(&r, x, y)) {
  1955.             return WINDOW_LB_LEFTARROW;
  1956.         }
  1957.         // check if on right arrow
  1958.         r.x = listPtr->listRect.x + listPtr->listRect.w - SCROLLBAR_SIZE;
  1959.         if (Rect_ContainsPoint(&r, x, y)) {
  1960.             return WINDOW_LB_RIGHTARROW;
  1961.         }
  1962.         // check if on thumb
  1963.         thumbstart = Item_ListBox_ThumbPosition(item);
  1964.         r.x = thumbstart;
  1965.         if (Rect_ContainsPoint(&r, x, y)) {
  1966.             return WINDOW_LB_THUMB;
  1967.         }
  1968.         r.x = listPtr->listRect.x + SCROLLBAR_SIZE;
  1969.         r.w = thumbstart - r.x;
  1970.         if (Rect_ContainsPoint(&r, x, y)) {
  1971.             return WINDOW_LB_PGUP;
  1972.         }
  1973.         r.x = thumbstart + SCROLLBAR_SIZE;
  1974.         r.w = listPtr->listRect.x + listPtr->listRect.w - SCROLLBAR_SIZE;
  1975.         if (Rect_ContainsPoint(&r, x, y)) {
  1976.             return WINDOW_LB_PGDN;
  1977.         }
  1978.     }
  1979.     else 
  1980.     {
  1981.         if ( item->type == ITEM_TYPE_COMBOBOX )
  1982.         {
  1983.             if ( !(item->window.flags & WINDOW_DROPPED ) )
  1984.             {
  1985.                 return 0;
  1986.             }
  1987.         }
  1988.             
  1989.         r.x = listPtr->listRect.x + listPtr->listRect.w - SCROLLBAR_SIZE;
  1990.         r.y = listPtr->listRect.y;
  1991.         r.h = r.w = SCROLLBAR_SIZE;
  1992.         if (Rect_ContainsPoint(&r, x, y)) {
  1993.             return WINDOW_LB_LEFTARROW;
  1994.         }
  1995.         r.y = listPtr->listRect.y + listPtr->listRect.h - SCROLLBAR_SIZE;
  1996.         if (Rect_ContainsPoint(&r, x, y)) {
  1997.             return WINDOW_LB_RIGHTARROW;
  1998.         }
  1999.         thumbstart = Item_ListBox_ThumbPosition(item);
  2000.         r.y = thumbstart;
  2001.         if (Rect_ContainsPoint(&r, x, y)) {
  2002.             return WINDOW_LB_THUMB;
  2003.         }
  2004.         r.y = listPtr->listRect.y + SCROLLBAR_SIZE;
  2005.         r.h = thumbstart - r.y;
  2006.         if (Rect_ContainsPoint(&r, x, y)) {
  2007.             return WINDOW_LB_PGUP;
  2008.         }
  2009.         r.y = thumbstart + SCROLLBAR_SIZE;
  2010.         r.h = listPtr->listRect.y + listPtr->listRect.h - SCROLLBAR_SIZE;
  2011.         if (Rect_ContainsPoint(&r, x, y)) {
  2012.             return WINDOW_LB_PGDN;
  2013.         }
  2014.     }
  2015.     return 0;
  2016. }
  2017.  
  2018.  
  2019. void Item_ListBox_MouseEnter(itemDef_t *item, float x, float y) 
  2020. {
  2021.     rectDef_t r;
  2022.     listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  2023.         
  2024.     item->window.flags &= ~(WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN);
  2025.     item->window.flags |= Item_ListBox_OverLB(item, x, y);
  2026.  
  2027.     if (item->window.flags & WINDOW_HORIZONTAL) 
  2028.     {
  2029.         if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) 
  2030.         {
  2031.             // check for selection hit as we have exausted buttons and thumb
  2032.             if (listPtr->elementStyle == LISTBOX_IMAGE) 
  2033.             {
  2034.                 r.x = listPtr->listRect.x;
  2035.                 r.y = listPtr->listRect.y;
  2036.                 r.h = listPtr->listRect.h - SCROLLBAR_SIZE;
  2037.                 r.w = listPtr->listRect.w - listPtr->drawPadding;
  2038.                 if (Rect_ContainsPoint(&r, x, y)) 
  2039.                 {
  2040.                     listPtr->cursorPos =  (int)((x - r.x) / listPtr->elementWidth)  + listPtr->startPos;
  2041.                     if (listPtr->cursorPos >= listPtr->endPos) 
  2042.                     {
  2043.                         listPtr->cursorPos = listPtr->endPos - 1;
  2044.                     }
  2045.                 }
  2046.             } 
  2047.             else 
  2048.             {
  2049.                 // text hit.. 
  2050.             }
  2051.         }
  2052.     } 
  2053.     else if (!(item->window.flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN))) 
  2054.     {
  2055.         r.x = listPtr->listRect.x;
  2056.         r.y = listPtr->listRect.y;
  2057.         r.w = listPtr->listRect.w - SCROLLBAR_SIZE;
  2058.         r.h = listPtr->listRect.h; //  - listPtr->drawPadding;
  2059.         if (Rect_ContainsPoint(&r, x, y)) 
  2060.         {            
  2061.             listPtr->cursorPos =  (int)((y - 2 - r.y) / listPtr->elementHeight)  + listPtr->startPos;
  2062.             if (listPtr->cursorPos >= listPtr->endPos) 
  2063.             {
  2064.                 listPtr->cursorPos = listPtr->endPos - 1;
  2065.             }
  2066.         }
  2067.     }
  2068. }
  2069.  
  2070. void Item_MouseEnter(itemDef_t *item, float x, float y) 
  2071. {
  2072.     rectDef_t r;
  2073.     if (!item) 
  2074.     {
  2075.         return;
  2076.     }
  2077.  
  2078.     r = item->textRect;
  2079.     r.y -= r.h;
  2080.     // in the text rect?
  2081.  
  2082.     if ( item->window.flags & WINDOW_DISABLED )
  2083.     {
  2084.         return;
  2085.     }
  2086.  
  2087.     // items can be enabled and disabled based on cvars
  2088.     if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) 
  2089.     {
  2090.         return;
  2091.     }
  2092.  
  2093.     if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(item, CVAR_SHOW)) 
  2094.     {
  2095.         return;
  2096.     }
  2097.  
  2098.     if (Rect_ContainsPoint(&r, x, y)) 
  2099.     {
  2100.         if (!(item->window.flags & WINDOW_MOUSEOVERTEXT)) 
  2101.         {
  2102.             Item_RunScript(item, item->mouseEnterText);
  2103.             item->window.flags |= WINDOW_MOUSEOVERTEXT;
  2104.         }
  2105.  
  2106.         if (!(item->window.flags & WINDOW_MOUSEOVER)) 
  2107.         {
  2108.             Item_RunScript(item, item->mouseEnter);
  2109.             Item_SetMouseOver ( item, qtrue );
  2110.         }
  2111.     } 
  2112.     else 
  2113.     {
  2114.         // not in the text rect
  2115.         if (item->window.flags & WINDOW_MOUSEOVERTEXT) 
  2116.         {
  2117.             // if we were
  2118.             Item_RunScript(item, item->mouseExitText);
  2119.             item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
  2120.         }
  2121.         
  2122.         if (!(item->window.flags & WINDOW_MOUSEOVER)) 
  2123.         {
  2124.             Item_RunScript(item, item->mouseEnter);
  2125.             Item_SetMouseOver ( item, qtrue );
  2126. //            item->window.flags |= WINDOW_MOUSEOVER;
  2127.         }
  2128.  
  2129.         switch ( item->type )
  2130.         {
  2131.             case ITEM_TYPE_COMBOBOX:
  2132.             case ITEM_TYPE_LISTBOX:
  2133.                 Item_ListBox_MouseEnter(item, x, y);
  2134.                 break;
  2135.             case ITEM_TYPE_TEXTSCROLL:
  2136.                 Item_TextScroll_MouseEnter ( item, x, y );
  2137.                 break;
  2138.         }
  2139.     }
  2140. }
  2141.  
  2142. void Item_MouseLeave(itemDef_t *item) 
  2143. {
  2144.     if (!item) 
  2145.     {
  2146.         return;
  2147.     }
  2148.  
  2149.     if (item->window.flags & WINDOW_MOUSEOVERTEXT) 
  2150.     {
  2151.         Item_RunScript(item, item->mouseExitText);
  2152.         item->window.flags &= ~WINDOW_MOUSEOVERTEXT;
  2153.     }
  2154.     
  2155.     Item_RunScript(item, item->mouseExit);
  2156.     item->window.flags &= ~(WINDOW_LB_RIGHTARROW | WINDOW_LB_LEFTARROW);
  2157. }
  2158.  
  2159. itemDef_t *Menu_HitTest(menuDef_t *menu, float x, float y) {
  2160.   int i;
  2161.   for (i = 0; i < menu->itemCount; i++) {
  2162.     if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
  2163.       return menu->items[i];
  2164.     }
  2165.   }
  2166.   return NULL;
  2167. }
  2168.  
  2169. qboolean Item_OwnerDraw_HandleKey(itemDef_t *item, int key) 
  2170. {
  2171.     if (item && DC->ownerDrawHandleKey) 
  2172.     {
  2173.         if ( key == K_MOUSE1 || key == K_MOUSE2 )
  2174.         {
  2175.             if ( !Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) ) 
  2176.             {
  2177.                 return qfalse;
  2178.             }
  2179.         }
  2180.  
  2181.         return DC->ownerDrawHandleKey(item->window.ownerDraw, item->window.ownerDrawFlags, &item->special, key, item->window.ownerDrawParam );
  2182.     }
  2183.     
  2184.     return qfalse;
  2185. }
  2186.  
  2187. void Item_ListBox_FeederSelection ( itemDef_t* item, qboolean force )
  2188. {
  2189.     // Only run selection when the click on an item or hit enter
  2190.     if ( !force && item->type == ITEM_TYPE_COMBOBOX )
  2191.     {
  2192.         return;
  2193.     }
  2194.  
  2195.     DC->feederSelection(item->special, item->cursorPos);
  2196.  
  2197.     // Undrop the window
  2198.     if ( item->window.flags & WINDOW_DROPPED )
  2199.     {
  2200.         item->window.flags &= (~WINDOW_DROPPED);
  2201.         Item_UpdatePosition ( item );
  2202.  
  2203.         itemExclusive = NULL;
  2204.  
  2205.         Menu_HandleMouseMove ( (menuDef_t*)item->parent, DC->cursorx, DC->cursory );
  2206.     }
  2207. }
  2208.  
  2209. qboolean Item_ListBox_HandleKey(itemDef_t *item, int key, qboolean down, qboolean force) 
  2210. {
  2211.     listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  2212.     int             count = DC->feederCount(item->special);
  2213.     int             max;
  2214.     int             viewmax;
  2215.  
  2216.     // Combo boxes have an extra button at the top to drop down the list
  2217.     if ( item->type == ITEM_TYPE_COMBOBOX && !itemCapture )
  2218.     {            
  2219.         // If its on the button then mark the combo box as dropped
  2220.         if ( Rect_ContainsPoint(&listPtr->comboRect, DC->cursorx, DC->cursory) )
  2221.         {
  2222.             itemExclusive = (item->window.flags&WINDOW_DROPPED)?NULL:item;
  2223.             item->window.flags ^= WINDOW_DROPPED;
  2224.             Item_UpdatePosition ( item );            
  2225.             return qtrue;
  2226.         }
  2227.  
  2228.         // If the combo box isnt droped then ignore the key
  2229.         if ( !(item->window.flags & WINDOW_DROPPED ) )
  2230.         {
  2231.             return qfalse;
  2232.         }
  2233.     }
  2234.  
  2235.     if ( force || (Rect_ContainsPoint(&listPtr->listRect, DC->cursorx, DC->cursory) && (item->window.flags & WINDOW_HASFOCUS))) 
  2236.     {
  2237.         max = Item_ListBox_MaxScroll(item);
  2238.         if (item->window.flags & WINDOW_HORIZONTAL) {
  2239.             viewmax = (listPtr->listRect.w / listPtr->elementWidth);
  2240.             if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) 
  2241.             {
  2242.                 if (!listPtr->notselectable) {
  2243.                     listPtr->cursorPos--;
  2244.                     if (listPtr->cursorPos < 0) {
  2245.                         listPtr->cursorPos = 0;
  2246.                     }
  2247.                     if (listPtr->cursorPos < listPtr->startPos) {
  2248.                         listPtr->startPos = listPtr->cursorPos;
  2249.                     }
  2250.                     if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
  2251.                         listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  2252.                     }
  2253.                     item->cursorPos = listPtr->cursorPos;
  2254.                     Item_ListBox_FeederSelection ( item, qfalse );
  2255.                 }
  2256.                 else {
  2257.                     listPtr->startPos--;
  2258.                     if (listPtr->startPos < 0)
  2259.                         listPtr->startPos = 0;
  2260.                 }
  2261.                 return qtrue;
  2262.             }
  2263.             if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) 
  2264.             {
  2265.                 if (!listPtr->notselectable) {
  2266.                     listPtr->cursorPos++;
  2267.                     if (listPtr->cursorPos < listPtr->startPos) {
  2268.                         listPtr->startPos = listPtr->cursorPos;
  2269.                     }
  2270.                     if (listPtr->cursorPos >= count) {
  2271.                         listPtr->cursorPos = count-1;
  2272.                     }
  2273.                     if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
  2274.                         listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  2275.                     }
  2276.                     item->cursorPos = listPtr->cursorPos;
  2277.                     Item_ListBox_FeederSelection ( item, qfalse );
  2278.                 }
  2279.                 else {
  2280.                     listPtr->startPos++;
  2281.                     if (listPtr->startPos >= count)
  2282.                         listPtr->startPos = count-1;
  2283.                 }
  2284.                 return qtrue;
  2285.             }
  2286.         }
  2287.         else {
  2288.             viewmax = (listPtr->listRect.h / listPtr->elementHeight);
  2289.             if ( key == K_UPARROW || key == K_KP_UPARROW ) 
  2290.             {
  2291.                 if (!listPtr->notselectable) {
  2292.                     listPtr->cursorPos--;
  2293.                     if (listPtr->cursorPos < 0) {
  2294.                         listPtr->cursorPos = 0;
  2295.                     }
  2296.                     if (listPtr->cursorPos < listPtr->startPos) {
  2297.                         listPtr->startPos = listPtr->cursorPos;
  2298.                     }
  2299.                     if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
  2300.                         listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  2301.                     }
  2302.                     item->cursorPos = listPtr->cursorPos;
  2303.                     Item_ListBox_FeederSelection ( item, qfalse );
  2304.                 }
  2305.                 else {
  2306.                     listPtr->startPos--;
  2307.                     if (listPtr->startPos < 0)
  2308.                         listPtr->startPos = 0;
  2309.                 }
  2310.                 return qtrue;
  2311.             }
  2312.             if ( key == K_DOWNARROW || key == K_KP_DOWNARROW ) 
  2313.             {
  2314.                 if (!listPtr->notselectable) {
  2315.                     listPtr->cursorPos++;
  2316.                     if (listPtr->cursorPos < listPtr->startPos) {
  2317.                         listPtr->startPos = listPtr->cursorPos;
  2318.                     }
  2319.                     if (listPtr->cursorPos >= count) {
  2320.                         listPtr->cursorPos = count-1;
  2321.                     }
  2322.                     if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
  2323.                         listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  2324.                     }
  2325.                     item->cursorPos = listPtr->cursorPos;
  2326.                     Item_ListBox_FeederSelection ( item, qfalse );
  2327.                 }
  2328.                 else {
  2329.                     listPtr->startPos++;
  2330.                     if (listPtr->startPos > max)
  2331.                         listPtr->startPos = max;
  2332.                 }
  2333.                 return qtrue;
  2334.             }
  2335.         }
  2336.  
  2337.         switch ( key )
  2338.         {
  2339.             case K_ENTER:
  2340.             case K_SPACE:
  2341.                 if ( item->type == ITEM_TYPE_COMBOBOX )
  2342.                 {
  2343.                     if ( !(item->window.flags & WINDOW_DROPPED ) )
  2344.                     {
  2345.                         itemExclusive = item;
  2346.                         item->window.flags |= WINDOW_DROPPED;
  2347.                         Item_UpdatePosition ( item );
  2348.                     }
  2349.                     else
  2350.                     {
  2351.                         Item_ListBox_FeederSelection ( item, qtrue );
  2352.                     }
  2353.  
  2354.                     return qtrue;
  2355.                 }
  2356.                 break;
  2357.  
  2358.             case K_MOUSE1:
  2359.             case K_MOUSE2:
  2360.             {
  2361.                 if (item->window.flags & WINDOW_LB_LEFTARROW) 
  2362.                 {
  2363.                     listPtr->startPos--;
  2364.                     if (listPtr->startPos < 0) 
  2365.                     {
  2366.                         listPtr->startPos = 0;
  2367.                     }
  2368.                 } 
  2369.                 else if (item->window.flags & WINDOW_LB_RIGHTARROW) 
  2370.                 {
  2371.                     // one down
  2372.                     listPtr->startPos++;
  2373.                     if (listPtr->startPos > max) {
  2374.                         listPtr->startPos = max;
  2375.                     }
  2376.                 } 
  2377.                 else if (item->window.flags & WINDOW_LB_PGUP) 
  2378.                 {
  2379.                     // page up
  2380.                     listPtr->startPos -= viewmax;
  2381.                     if (listPtr->startPos < 0) 
  2382.                     {
  2383.                         listPtr->startPos = 0;
  2384.                     }
  2385.                 } 
  2386.                 else if (item->window.flags & WINDOW_LB_PGDN) 
  2387.                 {
  2388.                     // page down
  2389.                     listPtr->startPos += viewmax;
  2390.                     if (listPtr->startPos > max) 
  2391.                     {
  2392.                         listPtr->startPos = max;
  2393.                     }
  2394.                 } 
  2395.                 else if (item->window.flags & WINDOW_LB_THUMB) 
  2396.                 {
  2397.                     // Display_SetCaptureItem(item);
  2398.                 } 
  2399.                 else 
  2400.                 {
  2401.                     // select an item
  2402.                     if (DC->realTime < lastListBoxClickTime && listPtr->doubleClick) 
  2403.                     {
  2404.                         Item_RunScript(item, listPtr->doubleClick);
  2405.                     }
  2406.  
  2407.                     lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY;
  2408.  
  2409.                     if (item->cursorPos != listPtr->cursorPos || item->type == ITEM_TYPE_COMBOBOX ) 
  2410.                     {
  2411.                         item->cursorPos = listPtr->cursorPos;
  2412.                         Item_ListBox_FeederSelection ( item, qtrue );
  2413.                     }
  2414.                 }
  2415.                 return qtrue;
  2416.             }
  2417.  
  2418.             case K_HOME:
  2419.             case K_KP_HOME:
  2420.                 // home
  2421.                 listPtr->startPos = 0;
  2422.                 return qtrue;
  2423.         
  2424.             case K_END:
  2425.             case K_KP_END:
  2426.                 // end
  2427.                 listPtr->startPos = max;
  2428.                 return qtrue;
  2429.  
  2430.             case K_PGUP:
  2431.             case K_KP_PGUP:
  2432.                 // page up
  2433.                 if (!listPtr->notselectable) 
  2434.                 {
  2435.                     listPtr->cursorPos -= viewmax;
  2436.                     if (listPtr->cursorPos < 0) 
  2437.                     {
  2438.                         listPtr->cursorPos = 0;
  2439.                     }
  2440.                     if (listPtr->cursorPos < listPtr->startPos) 
  2441.                     {
  2442.                         listPtr->startPos = listPtr->cursorPos;
  2443.                     }
  2444.                     if (listPtr->cursorPos >= listPtr->startPos + viewmax) 
  2445.                     {
  2446.                         listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  2447.                     }
  2448.                     item->cursorPos = listPtr->cursorPos;
  2449.                     Item_ListBox_FeederSelection ( item, qfalse );
  2450.                 }
  2451.                 else 
  2452.                 {
  2453.                     listPtr->startPos -= viewmax;
  2454.                     if (listPtr->startPos < 0) 
  2455.                     {
  2456.                         listPtr->startPos = 0;
  2457.                     }
  2458.                 }
  2459.             
  2460.                 return qtrue;
  2461.  
  2462.             case K_PGDN:
  2463.             case K_KP_PGDN:
  2464.                 // page down
  2465.                 if (!listPtr->notselectable) 
  2466.                 {
  2467.                     listPtr->cursorPos += viewmax;
  2468.                     if (listPtr->cursorPos < listPtr->startPos) {
  2469.                         listPtr->startPos = listPtr->cursorPos;
  2470.                     }
  2471.                     if (listPtr->cursorPos >= count) {
  2472.                         listPtr->cursorPos = count-1;
  2473.                     }
  2474.                     if (listPtr->cursorPos >= listPtr->startPos + viewmax) {
  2475.                         listPtr->startPos = listPtr->cursorPos - viewmax + 1;
  2476.                     }
  2477.                     item->cursorPos = listPtr->cursorPos;
  2478.                     Item_ListBox_FeederSelection ( item, qfalse );
  2479.                 }
  2480.                 else {
  2481.                     listPtr->startPos += viewmax;
  2482.                     if (listPtr->startPos > max) {
  2483.                         listPtr->startPos = max;
  2484.                     }
  2485.                 }
  2486.                 return qtrue;    
  2487.         }
  2488.     }
  2489.     else if ( !itemCapture && item->type == ITEM_TYPE_COMBOBOX && (item->window.flags & WINDOW_DROPPED) )
  2490.     {
  2491.         if ( key == K_MOUSE1 || key == K_MOUSE2 )
  2492.         {
  2493.             item->window.flags &= ~WINDOW_DROPPED;
  2494.             Item_UpdatePosition ( item );
  2495.  
  2496.             itemExclusive = NULL;
  2497.  
  2498.             Menu_HandleMouseMove ( (menuDef_t*)item->parent, DC->cursorx, DC->cursory );
  2499.  
  2500.             return qtrue;
  2501.         }
  2502.     }
  2503.  
  2504.     return qfalse;
  2505. }
  2506.  
  2507. qboolean Item_YesNo_HandleKey(itemDef_t *item, int key) {
  2508.  
  2509.   if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
  2510.         if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
  2511.         DC->setCVar(item->cvar, va("%i", !DC->getCVarValue(item->cvar)));
  2512.           return qtrue;
  2513.         }
  2514.   }
  2515.  
  2516.   return qfalse;
  2517.  
  2518. }
  2519.  
  2520. int Item_Multi_CountSettings(itemDef_t *item) {
  2521.     multiDef_t *multiPtr = (multiDef_t*)item->typeData;
  2522.     if (multiPtr == NULL) {
  2523.         return 0;
  2524.     }
  2525.     return multiPtr->count;
  2526. }
  2527.  
  2528. int Item_Multi_FindCvarByValue(itemDef_t *item) {
  2529.     char buff[1024];
  2530.     float value = 0;
  2531.     int i;
  2532.     multiDef_t *multiPtr = (multiDef_t*)item->typeData;
  2533.     if (multiPtr) {
  2534.         if (multiPtr->strDef) {
  2535.         DC->getCVarString(item->cvar, buff, sizeof(buff));
  2536.         } else {
  2537.             value = DC->getCVarValue(item->cvar);
  2538.         }
  2539.         for (i = 0; i < multiPtr->count; i++) {
  2540.             if (multiPtr->strDef) {
  2541.                 if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
  2542.                     return i;
  2543.                 }
  2544.             } else {
  2545.                  if (multiPtr->cvarValue[i] == value) {
  2546.                      return i;
  2547.                  }
  2548.              }
  2549.          }
  2550.     }
  2551.     return 0;
  2552. }
  2553.  
  2554. const char *Item_Multi_Setting(itemDef_t *item) {
  2555.     char buff[1024];
  2556.     float value = 0;
  2557.     int i;
  2558.     multiDef_t *multiPtr = (multiDef_t*)item->typeData;
  2559.     if (multiPtr) {
  2560.         if (multiPtr->strDef) {
  2561.         DC->getCVarString(item->cvar, buff, sizeof(buff));
  2562.         } else {
  2563.             value = DC->getCVarValue(item->cvar);
  2564.         }
  2565.         for (i = 0; i < multiPtr->count; i++) {
  2566.             if (multiPtr->strDef) {
  2567.                 if (Q_stricmp(buff, multiPtr->cvarStr[i]) == 0) {
  2568.                     return multiPtr->cvarList[i];
  2569.                 }
  2570.             } else {
  2571.                  if (multiPtr->cvarValue[i] == value) {
  2572.                     return multiPtr->cvarList[i];
  2573.                  }
  2574.              }
  2575.          }
  2576.     }
  2577.     return "Custom";
  2578. }
  2579.  
  2580. qboolean Item_Multi_HandleKey(itemDef_t *item, int key) {
  2581.     multiDef_t *multiPtr = (multiDef_t*)item->typeData;
  2582.     if (multiPtr) {
  2583.       if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && item->window.flags & WINDOW_HASFOCUS && item->cvar) {
  2584.             if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) {
  2585.                 int current = Item_Multi_FindCvarByValue(item) + 1;
  2586.                 int max = Item_Multi_CountSettings(item);
  2587.                 if ( current < 0 || current >= max ) {
  2588.                     current = 0;
  2589.                 }
  2590.                 if (multiPtr->strDef) {
  2591.                     DC->setCVar(item->cvar, multiPtr->cvarStr[current]);
  2592.                 } else {
  2593.                     float value = multiPtr->cvarValue[current];
  2594.                     if (((float)((int) value)) == value) {
  2595.                         DC->setCVar(item->cvar, va("%i", (int) value ));
  2596.                     }
  2597.                     else {
  2598.                         DC->setCVar(item->cvar, va("%f", value ));
  2599.                     }
  2600.                 }
  2601.                 return qtrue;
  2602.             }
  2603.         }
  2604.     }
  2605.   return qfalse;
  2606. }
  2607.  
  2608. qboolean Item_TextField_HandleKey(itemDef_t *item, int key) {
  2609.     char buff[1024];
  2610.     int len;
  2611.     editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
  2612.  
  2613.     if (item->cvar) {
  2614.  
  2615.         memset(buff, 0, sizeof(buff));
  2616.         DC->getCVarString(item->cvar, buff, sizeof(buff));
  2617.         len = strlen(buff);
  2618.         if (editPtr->maxChars && len > editPtr->maxChars) {
  2619.             len = editPtr->maxChars;
  2620.         }
  2621.         if ( key & K_CHAR_FLAG ) {
  2622.             key &= ~K_CHAR_FLAG;
  2623.  
  2624.  
  2625.             if (key == 'h' - 'a' + 1 )    {    // ctrl-h is backspace
  2626.                 if ( item->cursorPos > 0 ) {
  2627.                     memmove( &buff[item->cursorPos - 1], &buff[item->cursorPos], len + 1 - item->cursorPos);
  2628.                     item->cursorPos--;
  2629.                     if (item->cursorPos < editPtr->paintOffset) {
  2630.                         editPtr->paintOffset--;
  2631.                     }
  2632.                 }
  2633.                 DC->setCVar(item->cvar, buff);
  2634.                 return qtrue;
  2635.             }
  2636.  
  2637.  
  2638.             //
  2639.             // ignore any non printable chars
  2640.             //
  2641.             if ( key < 32 || !item->cvar) {
  2642.                 return qtrue;
  2643.             }
  2644.  
  2645.             if (item->type == ITEM_TYPE_NUMERICFIELD) {
  2646.                 if (key < '0' || key > '9') {
  2647.                     return qfalse;
  2648.                 }
  2649.             }
  2650.  
  2651.             if (!DC->getOverstrikeMode()) {
  2652.                 if (( len == MAX_EDITFIELD - 1 ) || (editPtr->maxChars && len >= editPtr->maxChars)) {
  2653.                     return qtrue;
  2654.                 }
  2655.                 memmove( &buff[item->cursorPos + 1], &buff[item->cursorPos], len + 1 - item->cursorPos );
  2656.             } else {
  2657.                 if (editPtr->maxChars && item->cursorPos >= editPtr->maxChars) {
  2658.                     return qtrue;
  2659.                 }
  2660.             }
  2661.  
  2662.             buff[item->cursorPos] = key;
  2663.  
  2664.             DC->setCVar(item->cvar, buff);
  2665.  
  2666.             if (item->cursorPos < len + 1) {
  2667.                 item->cursorPos++;
  2668.                 if (editPtr->maxPaintChars && item->cursorPos > editPtr->maxPaintChars) {
  2669.                     editPtr->paintOffset++;
  2670.                 }
  2671.             }
  2672.  
  2673.         } else {
  2674.  
  2675.             if ( key == K_DEL || key == K_KP_DEL ) {
  2676.                 if ( item->cursorPos < len ) {
  2677.                     memmove( buff + item->cursorPos, buff + item->cursorPos + 1, len - item->cursorPos);
  2678.                     DC->setCVar(item->cvar, buff);
  2679.                 }
  2680.                 return qtrue;
  2681.             }
  2682.  
  2683.             if ( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) 
  2684.             {
  2685.                 if (editPtr->maxPaintChars && item->cursorPos >= editPtr->maxPaintChars && item->cursorPos < len) {
  2686.                     item->cursorPos++;
  2687.                     editPtr->paintOffset++;
  2688.                     return qtrue;
  2689.                 }
  2690.                 if (item->cursorPos < len) {
  2691.                     item->cursorPos++;
  2692.                 } 
  2693.                 return qtrue;
  2694.             }
  2695.  
  2696.             if ( key == K_LEFTARROW || key == K_KP_LEFTARROW ) 
  2697.             {
  2698.                 if ( item->cursorPos > 0 ) {
  2699.                     item->cursorPos--;
  2700.                 }
  2701.                 if (item->cursorPos < editPtr->paintOffset) {
  2702.                     editPtr->paintOffset--;
  2703.                 }
  2704.                 return qtrue;
  2705.             }
  2706.  
  2707.             if ( key == K_HOME || key == K_KP_HOME) {// || ( tolower(key) == 'a' && trap_Key_IsDown( K_CTRL ) ) ) {
  2708.                 item->cursorPos = 0;
  2709.                 editPtr->paintOffset = 0;
  2710.                 return qtrue;
  2711.             }
  2712.  
  2713.             if ( key == K_END || key == K_KP_END)  {// ( tolower(key) == 'e' && trap_Key_IsDown( K_CTRL ) ) ) {
  2714.                 item->cursorPos = len;
  2715.                 if(item->cursorPos > editPtr->maxPaintChars) {
  2716.                     editPtr->paintOffset = len - editPtr->maxPaintChars;
  2717.                 }
  2718.                 return qtrue;
  2719.             }
  2720.  
  2721.             if ( key == K_INS || key == K_KP_INS ) {
  2722.                 DC->setOverstrikeMode(!DC->getOverstrikeMode());
  2723.                 return qtrue;
  2724.             }
  2725.         }
  2726.  
  2727.         if (key == K_TAB || key == K_DOWNARROW || key == K_KP_DOWNARROW) 
  2728.         {
  2729.             g_editingField = qfalse;
  2730.             g_editItem = NULL;
  2731.         }
  2732.  
  2733.         if (key == K_UPARROW || key == K_KP_UPARROW) 
  2734.         {
  2735.             g_editingField = qfalse;
  2736.             g_editItem = NULL;
  2737.         }
  2738.  
  2739.         if ( key == K_ENTER || key == K_KP_ENTER || key == K_ESCAPE)  {
  2740.             return qfalse;
  2741.         }
  2742.  
  2743.         return qtrue;
  2744.     }
  2745.     return qfalse;
  2746.  
  2747. }
  2748.  
  2749. static void Scroll_TextScroll_AutoFunc (void *p) 
  2750. {
  2751.     scrollInfo_t *si = (scrollInfo_t*)p;
  2752.  
  2753.     if (DC->realTime > si->nextScrollTime) 
  2754.     { 
  2755.         // need to scroll which is done by simulating a click to the item
  2756.         // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
  2757.         // so it calls it directly
  2758.         Item_TextScroll_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
  2759.         si->nextScrollTime = DC->realTime + si->adjustValue; 
  2760.     }
  2761.  
  2762.     if (DC->realTime > si->nextAdjustTime) 
  2763.     {
  2764.         si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
  2765.         if (si->adjustValue > SCROLL_TIME_FLOOR) 
  2766.         {
  2767.             si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
  2768.         }
  2769.     }
  2770. }
  2771.  
  2772. static void Scroll_TextScroll_ThumbFunc(void *p) 
  2773. {
  2774.     scrollInfo_t *si = (scrollInfo_t*)p;
  2775.     rectDef_t     r;
  2776.     int             pos;
  2777.     int             max;
  2778.  
  2779.     textScrollDef_t *scrollPtr = (textScrollDef_t*)si->item->typeData;
  2780.  
  2781.     if (DC->cursory != si->yStart) 
  2782.     {
  2783.         r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1;
  2784.         r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1;
  2785.         r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2;
  2786.         r.w = SCROLLBAR_SIZE;
  2787.         max = Item_TextScroll_MaxScroll(si->item);
  2788.         //
  2789.         pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE);
  2790.         if (pos < 0) 
  2791.         {
  2792.             pos = 0;
  2793.         }
  2794.         else if (pos > max) 
  2795.         {
  2796.             pos = max;
  2797.         }
  2798.  
  2799.         scrollPtr->startPos = pos;
  2800.         si->yStart = DC->cursory;
  2801.     }
  2802.  
  2803.     if (DC->realTime > si->nextScrollTime) 
  2804.     { 
  2805.         // need to scroll which is done by simulating a click to the item
  2806.         // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
  2807.         // so it calls it directly
  2808.         Item_TextScroll_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
  2809.         si->nextScrollTime = DC->realTime + si->adjustValue; 
  2810.     }
  2811.  
  2812.     if (DC->realTime > si->nextAdjustTime) 
  2813.     {
  2814.         si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
  2815.         if (si->adjustValue > SCROLL_TIME_FLOOR) 
  2816.         {
  2817.             si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
  2818.         }
  2819.     }
  2820. }
  2821.  
  2822. static void Scroll_ListBox_AutoFunc(void *p) {
  2823.     scrollInfo_t *si = (scrollInfo_t*)p;
  2824.     if (DC->realTime > si->nextScrollTime) { 
  2825.         // need to scroll which is done by simulating a click to the item
  2826.         // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
  2827.         // so it calls it directly
  2828.         Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
  2829.         si->nextScrollTime = DC->realTime + si->adjustValue; 
  2830.     }
  2831.  
  2832.     if (DC->realTime > si->nextAdjustTime) {
  2833.         si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
  2834.         if (si->adjustValue > SCROLL_TIME_FLOOR) {
  2835.             si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
  2836.         }
  2837.     }
  2838. }
  2839.  
  2840. static void Scroll_ListBox_ThumbFunc(void *p) {
  2841.     scrollInfo_t *si = (scrollInfo_t*)p;
  2842.     rectDef_t r;
  2843.     int pos, max;
  2844.  
  2845.     listBoxDef_t *listPtr = (listBoxDef_t*)si->item->typeData;
  2846.     if (si->item->window.flags & WINDOW_HORIZONTAL) {
  2847.         if (DC->cursorx == si->xStart) {
  2848.             return;
  2849.         }
  2850.         r.x = si->item->window.rect.x + SCROLLBAR_SIZE + 1;
  2851.         r.y = si->item->window.rect.y + si->item->window.rect.h - SCROLLBAR_SIZE - 1;
  2852.         r.h = SCROLLBAR_SIZE;
  2853.         r.w = si->item->window.rect.w - (SCROLLBAR_SIZE*2) - 2;
  2854.         max = Item_ListBox_MaxScroll(si->item);
  2855.         //
  2856.         pos = (DC->cursorx - r.x - SCROLLBAR_SIZE/2) * max / (r.w - SCROLLBAR_SIZE);
  2857.         if (pos < 0) {
  2858.             pos = 0;
  2859.         }
  2860.         else if (pos > max) {
  2861.             pos = max;
  2862.         }
  2863.         listPtr->startPos = pos;
  2864.         si->xStart = DC->cursorx;
  2865.     }
  2866.     else if (DC->cursory != si->yStart) {
  2867.  
  2868.         r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_SIZE - 1;
  2869.         r.y = si->item->window.rect.y + SCROLLBAR_SIZE + 1;
  2870.         r.h = si->item->window.rect.h - (SCROLLBAR_SIZE*2) - 2;
  2871.         r.w = SCROLLBAR_SIZE;
  2872.         max = Item_ListBox_MaxScroll(si->item);
  2873.         //
  2874.         pos = (DC->cursory - r.y - SCROLLBAR_SIZE/2) * max / (r.h - SCROLLBAR_SIZE);
  2875.         if (pos < 0) {
  2876.             pos = 0;
  2877.         }
  2878.         else if (pos > max) {
  2879.             pos = max;
  2880.         }
  2881.         listPtr->startPos = pos;
  2882.         si->yStart = DC->cursory;
  2883.     }
  2884.  
  2885.     if (DC->realTime > si->nextScrollTime) { 
  2886.         // need to scroll which is done by simulating a click to the item
  2887.         // this is done a bit sideways as the autoscroll "knows" that the item is a listbox
  2888.         // so it calls it directly
  2889.         Item_ListBox_HandleKey(si->item, si->scrollKey, qtrue, qfalse);
  2890.         si->nextScrollTime = DC->realTime + si->adjustValue; 
  2891.     }
  2892.  
  2893.     if (DC->realTime > si->nextAdjustTime) {
  2894.         si->nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
  2895.         if (si->adjustValue > SCROLL_TIME_FLOOR) {
  2896.             si->adjustValue -= SCROLL_TIME_ADJUSTOFFSET;
  2897.         }
  2898.     }
  2899. }
  2900.  
  2901. static void Scroll_Slider_ThumbFunc ( void *p ) 
  2902. {
  2903.     float            x;
  2904.     float            value;
  2905.     float            cursorx;
  2906.     scrollInfo_t    *si = (scrollInfo_t*)p;
  2907.     editFieldDef_t    *editDef = si->item->typeData;
  2908.  
  2909.     if (si->item->text && *si->item->text) 
  2910.     {
  2911.         x = si->item->textRect.x + si->item->textRect.w + 8;
  2912.     } 
  2913.     else 
  2914.     {
  2915.         x = si->item->window.rect.x;
  2916.         x += (SLIDER_THUMB_WIDTH / 2);
  2917.     }
  2918.  
  2919.     cursorx = DC->cursorx;
  2920.  
  2921.     if (cursorx < x) 
  2922.     {
  2923.         cursorx = x;
  2924.     } 
  2925.     else if (cursorx > x + SLIDER_WIDTH - SLIDER_THUMB_WIDTH) 
  2926.     {
  2927.         cursorx = x + SLIDER_WIDTH - SLIDER_THUMB_WIDTH;
  2928.     }
  2929.     
  2930.     value = cursorx - x;
  2931.     value /= (SLIDER_WIDTH - SLIDER_THUMB_WIDTH);
  2932.     value *= (editDef->maxVal - editDef->minVal);
  2933.     value += editDef->minVal;
  2934.  
  2935.     DC->setCVar(si->item->cvar, va("%f", value));
  2936. }
  2937.  
  2938. void Item_StartCapture(itemDef_t *item, int key) {
  2939.     int flags;
  2940.     switch (item->type) {
  2941.         case ITEM_TYPE_EDITFIELD:
  2942.         case ITEM_TYPE_PASSWORDFIELD:
  2943.         case ITEM_TYPE_NUMERICFIELD:
  2944.             break;
  2945.  
  2946.         case ITEM_TYPE_COMBOBOX:
  2947.         case ITEM_TYPE_LISTBOX:
  2948.         {
  2949.             flags = Item_ListBox_OverLB(item, DC->cursorx, DC->cursory);
  2950.             if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) {
  2951.                 scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START;
  2952.                 scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
  2953.                 scrollInfo.adjustValue = SCROLL_TIME_START;
  2954.                 scrollInfo.scrollKey = key;
  2955.                 scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse;
  2956.                 scrollInfo.item = item;
  2957.                 captureData = &scrollInfo;
  2958.                 captureFunc = &Scroll_ListBox_AutoFunc;
  2959.                 itemCapture = item;
  2960.             } else if (flags & WINDOW_LB_THUMB) {
  2961.                 scrollInfo.scrollKey = key;
  2962.                 scrollInfo.item = item;
  2963.                 scrollInfo.xStart = DC->cursorx;
  2964.                 scrollInfo.yStart = DC->cursory;
  2965.                 captureData = &scrollInfo;
  2966.                 captureFunc = &Scroll_ListBox_ThumbFunc;
  2967.                 itemCapture = item;
  2968.             }
  2969.             break;
  2970.         }
  2971.         case ITEM_TYPE_TEXTSCROLL:
  2972.             flags = Item_TextScroll_OverLB (item, DC->cursorx, DC->cursory);
  2973.             if (flags & (WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW)) 
  2974.             {
  2975.                 scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START;
  2976.                 scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST;
  2977.                 scrollInfo.adjustValue = SCROLL_TIME_START;
  2978.                 scrollInfo.scrollKey = key;
  2979.                 scrollInfo.scrollDir = (flags & WINDOW_LB_LEFTARROW) ? qtrue : qfalse;
  2980.                 scrollInfo.item = item;
  2981.                 captureData = &scrollInfo;
  2982.                 captureFunc = &Scroll_TextScroll_AutoFunc;
  2983.                 itemCapture = item;
  2984.             } 
  2985.             else if (flags & WINDOW_LB_THUMB) 
  2986.             {
  2987.                 scrollInfo.scrollKey = key;
  2988.                 scrollInfo.item = item;
  2989.                 scrollInfo.xStart = DC->cursorx;
  2990.                 scrollInfo.yStart = DC->cursory;
  2991.                 captureData = &scrollInfo;
  2992.                 captureFunc = &Scroll_TextScroll_ThumbFunc;
  2993.                 itemCapture = item;
  2994.             }
  2995.             break;
  2996.  
  2997.         case ITEM_TYPE_SLIDER:
  2998.         {
  2999.             flags = Item_Slider_OverSlider(item, DC->cursorx, DC->cursory);
  3000.             if (flags & WINDOW_LB_THUMB) {
  3001.                 scrollInfo.scrollKey = key;
  3002.                 scrollInfo.item = item;
  3003.                 scrollInfo.xStart = DC->cursorx;
  3004.                 scrollInfo.yStart = DC->cursory;
  3005.                 captureData = &scrollInfo;
  3006.                 captureFunc = &Scroll_Slider_ThumbFunc;
  3007.                 itemCapture = item;
  3008.             }
  3009.             break;
  3010.         }
  3011.     }
  3012. }
  3013.  
  3014. void Item_StopCapture(itemDef_t *item) {
  3015.  
  3016.     Item_RunScript ( item, item->action );
  3017.  
  3018. }
  3019.  
  3020. qboolean Item_Slider_HandleKey ( itemDef_t *item, int key, qboolean down )
  3021. {
  3022.     float x, value, width, work;
  3023.  
  3024.     if (item->window.flags & WINDOW_HASFOCUS && item->cvar && Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) 
  3025.     {
  3026.         if (key == K_MOUSE1 || key == K_ENTER || key == K_MOUSE2 || key == K_MOUSE3) 
  3027.         {
  3028.             editFieldDef_t *editDef = item->typeData;
  3029.             if (editDef) 
  3030.             {
  3031.                 width = (SLIDER_WIDTH - SLIDER_THUMB_WIDTH);
  3032.                 
  3033.                 if (item->text && *item->text) 
  3034.                 {
  3035.                     x = item->textRect.x + item->textRect.w + 8;
  3036.                 } 
  3037.                 else 
  3038.                 {
  3039.                     x = item->window.rect.x + (SLIDER_THUMB_WIDTH/2);
  3040.                 }
  3041.  
  3042.                 if ( DC->cursorx <= x )
  3043.                 {
  3044.                     value = editDef->minVal;
  3045.                 }
  3046.                 else if ( DC->cursorx >= x + width )
  3047.                 {
  3048.                     value = editDef->maxVal;
  3049.                 }
  3050.                 else
  3051.                 {
  3052.                     work = DC->cursorx - x + 1;
  3053.                     value = work / width;
  3054.                     value *= (editDef->maxVal - editDef->minVal);
  3055.                     value += editDef->minVal;
  3056.                 }
  3057.                     
  3058.                 DC->setCVar(item->cvar, va("%f", value));
  3059.                 return qtrue;
  3060.             }
  3061.         }
  3062.     }
  3063.  
  3064.     return qfalse;
  3065. }
  3066.  
  3067.  
  3068. qboolean Item_HandleKey ( itemDef_t *item, int key, qboolean down )
  3069. {
  3070.     if (itemCapture) 
  3071.     {
  3072.         Item_StopCapture(itemCapture);
  3073.         itemCapture = NULL;
  3074.         captureFunc = NULL;
  3075.         captureData = NULL;
  3076.     } 
  3077.     else 
  3078.     {
  3079.       // bk001206 - parentheses
  3080.         if ( down && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) 
  3081.         {
  3082.             Item_StartCapture(item, key);
  3083.         }
  3084.     }
  3085.  
  3086.     if (!down) 
  3087.     {
  3088.         return qfalse;
  3089.     }
  3090.  
  3091.     switch (item->type) 
  3092.     {
  3093.         case ITEM_TYPE_BUTTON:
  3094.             if(item->hotKey && item->hotKey == key )
  3095.             {
  3096.                 return qfalse;
  3097.             }
  3098.             return qfalse;
  3099.             break;
  3100.  
  3101.         case ITEM_TYPE_RADIOBUTTON:
  3102.             return qfalse;
  3103.  
  3104.         case ITEM_TYPE_CHECKBOX:
  3105.             return qfalse;
  3106.  
  3107.         case ITEM_TYPE_PASSWORDFIELD:
  3108.         case ITEM_TYPE_EDITFIELD:
  3109.         case ITEM_TYPE_NUMERICFIELD:
  3110.             //return Item_TextField_HandleKey(item, key);
  3111.             return qfalse;
  3112.  
  3113.         case ITEM_TYPE_COMBO:
  3114.             return qfalse;
  3115.         
  3116.         case ITEM_TYPE_COMBOBOX:
  3117.         case ITEM_TYPE_LISTBOX:
  3118.             return Item_ListBox_HandleKey(item, key, down, qfalse);
  3119.  
  3120.         case ITEM_TYPE_TEXTSCROLL:
  3121.           return Item_TextScroll_HandleKey(item, key, down, qfalse);
  3122.           break;
  3123.  
  3124.         case ITEM_TYPE_YESNO:
  3125.             return Item_YesNo_HandleKey(item, key);
  3126.  
  3127.         case ITEM_TYPE_MULTI:
  3128.             return Item_Multi_HandleKey(item, key);
  3129.  
  3130.         case ITEM_TYPE_OWNERDRAW:
  3131.             return Item_OwnerDraw_HandleKey(item, key);
  3132.  
  3133.         case ITEM_TYPE_BIND:
  3134.             return Item_Bind_HandleKey(item, key, down);
  3135.       
  3136.         case ITEM_TYPE_SLIDER:
  3137.             return Item_Slider_HandleKey(item, key, down);
  3138.     }
  3139.  
  3140.     return qfalse;
  3141. }
  3142.  
  3143. void Item_Action(itemDef_t *item) 
  3144. {
  3145.     if (item) 
  3146.     {
  3147.         Item_RunScript(item, item->action);
  3148.     }
  3149. }
  3150.  
  3151. itemDef_t *Menu_SetPrevCursorItem(menuDef_t *menu) {
  3152.   qboolean wrapped = qfalse;
  3153.     int oldCursor = menu->cursorItem;
  3154.   
  3155.   if (menu->cursorItem < 0) {
  3156.     menu->cursorItem = menu->itemCount-1;
  3157.     wrapped = qtrue;
  3158.   } 
  3159.  
  3160.   while (menu->cursorItem > -1) {
  3161.     
  3162.     menu->cursorItem--;
  3163.     if (menu->cursorItem < 0 && !wrapped) {
  3164.       wrapped = qtrue;
  3165.       menu->cursorItem = menu->itemCount -1;
  3166.     }
  3167.  
  3168.         if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
  3169.             Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
  3170.       return menu->items[menu->cursorItem];
  3171.     }
  3172.   }
  3173.     menu->cursorItem = oldCursor;
  3174.     return NULL;
  3175.  
  3176. }
  3177.  
  3178. itemDef_t *Menu_SetNextCursorItem(menuDef_t *menu) {
  3179.  
  3180.   qboolean wrapped = qfalse;
  3181.     int oldCursor = menu->cursorItem;
  3182.  
  3183.  
  3184.   if (menu->cursorItem == -1) {
  3185.     menu->cursorItem = 0;
  3186.     wrapped = qtrue;
  3187.   }
  3188.  
  3189.   while (menu->cursorItem < menu->itemCount) {
  3190.  
  3191.     menu->cursorItem++;
  3192.     if (menu->cursorItem >= menu->itemCount && !wrapped) {
  3193.       wrapped = qtrue;
  3194.       menu->cursorItem = 0;
  3195.     }
  3196.         if (Item_SetFocus(menu->items[menu->cursorItem], DC->cursorx, DC->cursory)) {
  3197.             Menu_HandleMouseMove(menu, menu->items[menu->cursorItem]->window.rect.x + 1, menu->items[menu->cursorItem]->window.rect.y + 1);
  3198.       return menu->items[menu->cursorItem];
  3199.     }
  3200.     
  3201.   }
  3202.  
  3203.     menu->cursorItem = oldCursor;
  3204.     return NULL;
  3205. }
  3206.  
  3207. static void Window_CloseCinematic(windowDef_t *window) {
  3208.     if (window->style == WINDOW_STYLE_CINEMATIC && window->cinematic >= 0) {
  3209.         DC->stopCinematic(window->cinematic);
  3210.         window->cinematic = -1;
  3211.     }
  3212. }
  3213.  
  3214. static void Menu_CloseCinematics(menuDef_t *menu) {
  3215.     if (menu) {
  3216.         int i;
  3217.         Window_CloseCinematic(&menu->window);
  3218.       for (i = 0; i < menu->itemCount; i++) {
  3219.           Window_CloseCinematic(&menu->items[i]->window);
  3220.             if (menu->items[i]->type == ITEM_TYPE_OWNERDRAW) {
  3221.                 DC->stopCinematic(0-menu->items[i]->window.ownerDraw);
  3222.             }
  3223.       }
  3224.     }
  3225. }
  3226.  
  3227. static void Display_CloseCinematics() {
  3228.     int i;
  3229.     for (i = 0; i < menuCount; i++) {
  3230.         Menu_CloseCinematics(&Menus[i]);
  3231.     }
  3232. }
  3233.  
  3234. void  Menus_Activate(menuDef_t *menu) 
  3235. {
  3236.     int i;
  3237.  
  3238.     menu->window.flags |= (WINDOW_HASFOCUS | WINDOW_VISIBLE);
  3239.  
  3240.     // Run the onOpen script if there is one
  3241.     if (menu->onOpen) 
  3242.     {
  3243.         itemDef_t item;
  3244.         item.parent = menu;
  3245.         Item_RunScript(&item, menu->onOpen);
  3246.     }
  3247.  
  3248.     if (menu->soundName && *menu->soundName) {
  3249. //        DC->stopBackgroundTrack();                    // you don't want to do this since it will reset s_rawend
  3250.         DC->startBackgroundTrack(menu->soundName, menu->soundName, qfalse);
  3251.     }
  3252.  
  3253.     menu->appearanceTime = 0;
  3254.     Display_CloseCinematics();
  3255.  
  3256.     // Close any combo boxes
  3257.     for ( i = 0; i < menu->itemCount ; i ++ )
  3258.     {
  3259.         if ( menu->items[i]->window.flags & WINDOW_DROPPED )
  3260.         {
  3261.             menu->items[i]->window.flags &= (~WINDOW_DROPPED);
  3262.             Item_UpdatePosition ( menu->items[i] );
  3263.         }
  3264.     }
  3265. }
  3266.  
  3267. int Display_VisibleMenuCount() {
  3268.     int i, count;
  3269.     count = 0;
  3270.     for (i = 0; i < menuCount; i++) {
  3271.         if (Menus[i].window.flags & (WINDOW_FORCED | WINDOW_VISIBLE)) {
  3272.             count++;
  3273.         }
  3274.     }
  3275.     return count;
  3276. }
  3277.  
  3278. void Menus_HandleOOBClick(menuDef_t *menu, int key, qboolean down) {
  3279.     if (menu) {
  3280.         int i;
  3281.         // basically the behaviour we are looking for is if there are windows in the stack.. see if 
  3282.         // the cursor is within any of them.. if not close them otherwise activate them and pass the 
  3283.         // key on.. force a mouse move to activate focus and script stuff 
  3284.         if (down && menu->window.flags & WINDOW_OOB_CLICK) {
  3285.             Menu_RunCloseScript(menu);
  3286.             menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
  3287.         }
  3288.  
  3289.         for (i = 0; i < menuCount; i++) {
  3290.             if (Menu_OverActiveItem(&Menus[i], DC->cursorx, DC->cursory)) {
  3291. //                Menu_RunCloseScript(menu);
  3292. //                menu->window.flags &= ~(WINDOW_HASFOCUS | WINDOW_VISIBLE);
  3293. //                menu->window.flags &= ~(WINDOW_HASFOCUS);
  3294. //                Menus_Activate(&Menus[i]);
  3295.                 Menu_HandleMouseMove(&Menus[i], DC->cursorx, DC->cursory);
  3296.                 Menu_HandleKey(&Menus[i], key, down);
  3297.             }
  3298.         }
  3299.  
  3300.         if (Display_VisibleMenuCount() == 0) {
  3301.             if (DC->Pause) {
  3302.                 DC->Pause(qfalse);
  3303.             }
  3304.         }
  3305.         Display_CloseCinematics();
  3306.     }
  3307. }
  3308.  
  3309. static rectDef_t *Item_CorrectedTextRect(itemDef_t *item) {
  3310.     static rectDef_t rect;
  3311.     memset(&rect, 0, sizeof(rectDef_t));
  3312.     if (item) {
  3313.         rect = item->textRect;
  3314.         if (rect.w) {
  3315.             rect.y -= rect.h;
  3316.         }
  3317.     }
  3318.     return ▭
  3319. }
  3320.  
  3321. qboolean Menu_HandleKey(menuDef_t *menu, int key, qboolean down) 
  3322. {
  3323.     int            i;
  3324.     itemDef_t    *item = NULL;
  3325.     qboolean    inHandler = qfalse;
  3326.  
  3327.     if (inHandler) 
  3328.     {
  3329.         return qfalse;
  3330.     }
  3331.  
  3332.     inHandler = qtrue;
  3333.     if (g_waitingForKey && down) 
  3334.     {
  3335.         qboolean handled = Item_Bind_HandleKey(g_bindItem, key, down);
  3336.         inHandler = qfalse;
  3337.         return handled;
  3338.     }
  3339.  
  3340.     if (g_editingField && down) 
  3341.     {
  3342.         if (!Item_TextField_HandleKey(g_editItem, key)) 
  3343.         {
  3344.             g_editingField = qfalse;
  3345.             g_editItem = NULL;
  3346.             inHandler = qfalse;
  3347.             return qfalse;
  3348.         } 
  3349.         else if (key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3) 
  3350.         {
  3351.             g_editingField = qfalse;
  3352.             g_editItem = NULL;
  3353.             Display_MouseMove(NULL, DC->cursorx, DC->cursory);
  3354.         } 
  3355.         else if (key == K_TAB || key == K_UPARROW || key == K_DOWNARROW) 
  3356.         {
  3357.             return qfalse;
  3358.         }
  3359.     }
  3360.  
  3361.     if (menu == NULL) 
  3362.     {
  3363.         inHandler = qfalse;
  3364.         return qfalse;
  3365.     }
  3366.  
  3367.         // see if the mouse is within the window bounds and if so is this a mouse click
  3368.     if (down && !(menu->window.flags & WINDOW_POPUP) && !Rect_ContainsPoint(&menu->window.rect, DC->cursorx, DC->cursory)) 
  3369.     {
  3370.         static qboolean inHandleKey = qfalse;
  3371.         // bk001206 - parentheses
  3372.         if (!inHandleKey && ( key == K_MOUSE1 || key == K_MOUSE2 || key == K_MOUSE3 ) ) 
  3373.         {
  3374.             inHandleKey = qtrue;
  3375.             Menus_HandleOOBClick(menu, key, down);
  3376.             inHandleKey = qfalse;
  3377.             inHandler = qfalse;
  3378.             return qfalse;
  3379.         }
  3380.     }
  3381.  
  3382.     // get the item with focus
  3383.     if ( itemExclusive )
  3384.     {
  3385.         item = itemExclusive;
  3386.     }
  3387.     else
  3388.     {
  3389.         for (i = 0; i < menu->itemCount; i++) 
  3390.         {
  3391.             if (menu->items[i]->window.flags & WINDOW_HASFOCUS) 
  3392.             {
  3393.                 item = menu->items[i];
  3394.             }
  3395.         }
  3396.     }
  3397.  
  3398.     if (item != NULL) 
  3399.     {
  3400.         if (Item_HandleKey(item, key, down)) 
  3401.         {
  3402.             Item_Action(item);
  3403.             inHandler = qfalse;
  3404.             return qtrue;
  3405.         }
  3406.     }
  3407.  
  3408.     if (!down) 
  3409.     {
  3410.         inHandler = qfalse;
  3411.         return qfalse;
  3412.     }
  3413.  
  3414.     // default handling
  3415.     switch ( key ) {
  3416.  
  3417.         case K_F11:
  3418.             if (DC->getCVarValue("developer")) {
  3419.                 debugMode ^= 1;
  3420.             }
  3421.             break;
  3422.  
  3423.         case K_F12:
  3424.             if (DC->getCVarValue("developer")) {
  3425.                 DC->executeText(EXEC_APPEND, "screenshot\n");
  3426.             }
  3427.             break;
  3428.         case K_LEFTARROW:
  3429.         case K_KP_LEFTARROW:
  3430.         case K_KP_UPARROW:
  3431.         case K_UPARROW:
  3432.             if ( !g_editingField )
  3433.             {
  3434.                 Menu_SetPrevCursorItem(menu);
  3435.             }
  3436.             break;
  3437.  
  3438.         case K_ESCAPE:
  3439.             if (!g_waitingForKey && menu->onESC) {
  3440.                 itemDef_t it;
  3441.             it.parent = menu;
  3442.             Item_RunScript(&it, menu->onESC);
  3443.             }
  3444.             break;
  3445.         case K_TAB:
  3446.         case K_RIGHTARROW:
  3447.         case K_KP_RIGHTARROW:
  3448.         case K_KP_DOWNARROW:
  3449.         case K_DOWNARROW:
  3450.             if ( !g_editingField )
  3451.             {
  3452.                 Menu_SetNextCursorItem(menu);
  3453.             }
  3454.             break;
  3455.  
  3456.         case K_MOUSE1:
  3457.         case K_MOUSE2:
  3458.  
  3459.             if (item) 
  3460.             {
  3461.                 if (item->type == ITEM_TYPE_TEXT) {
  3462.                     if (Rect_ContainsPoint(Item_CorrectedTextRect(item), DC->cursorx, DC->cursory)) {
  3463.                         Item_Action(item);
  3464.                     }
  3465.                 } else if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD || item->type == ITEM_TYPE_PASSWORDFIELD) {
  3466.                     if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
  3467.                         item->cursorPos = 0;
  3468.                         g_editingField = qtrue;
  3469.                         g_editItem = item;
  3470.                         DC->setOverstrikeMode(qtrue);
  3471.                     }
  3472.                 } else {
  3473.                     if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory)) {
  3474.                         Item_Action(item);
  3475.                     }
  3476.                 }
  3477.             }
  3478.             break;
  3479.  
  3480.         case K_JOY1:
  3481.         case K_JOY2:
  3482.         case K_JOY3:
  3483.         case K_JOY4:
  3484.         case K_AUX1:
  3485.         case K_AUX2:
  3486.         case K_AUX3:
  3487.         case K_AUX4:
  3488.         case K_AUX5:
  3489.         case K_AUX6:
  3490.         case K_AUX7:
  3491.         case K_AUX8:
  3492.         case K_AUX9:
  3493.         case K_AUX10:
  3494.         case K_AUX11:
  3495.         case K_AUX12:
  3496.         case K_AUX13:
  3497.         case K_AUX14:
  3498.         case K_AUX15:
  3499.         case K_AUX16:
  3500.             break;
  3501.         case K_KP_ENTER:
  3502.         case K_ENTER:
  3503.             if (item) {
  3504.                 if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_NUMERICFIELD || item->type == ITEM_TYPE_PASSWORDFIELD ) {
  3505.                     item->cursorPos = 0;
  3506.                     g_editingField = qtrue;
  3507.                     g_editItem = item;
  3508.                     DC->setOverstrikeMode(qtrue);
  3509.                 } else {
  3510.                         Item_Action(item);
  3511.                 }
  3512.             }
  3513.             break;
  3514.  
  3515.         default:
  3516.  
  3517.             // See if a hotkey was pressed.
  3518.             for (i = 0; i < menu->itemCount; i++) 
  3519.             {
  3520.                 if ( menu->items[i]->window.flags & WINDOW_DISABLED )
  3521.                 {
  3522.                     continue;
  3523.                 }
  3524.  
  3525.                 if ((menu->items[i]->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE)) && !Item_EnableShowViaCvar(menu->items[i], CVAR_ENABLE) )
  3526.                 {
  3527.                     continue;
  3528.                 }
  3529.  
  3530.                 if ( !(menu->items[i]->window.flags & WINDOW_VISIBLE) )
  3531.                 {
  3532.                     continue;
  3533.                 }
  3534.  
  3535.                 if (menu->items[i]->hotKey == key ) 
  3536.                 {
  3537.                     Item_OwnerDraw_HandleKey ( menu->items[i], K_ENTER );
  3538.                     Item_Action(menu->items[i]);
  3539.                     inHandler = qfalse;
  3540.                     return qtrue;
  3541.                 }
  3542.             }
  3543.             break;
  3544.  
  3545.     }
  3546.     inHandler = qfalse;
  3547.  
  3548.     return qfalse;
  3549. }
  3550.  
  3551. void ToWindowCoords(float *x, float *y, windowDef_t *window) {
  3552.     if (window->border != 0) {
  3553.         *x += window->borderSize;
  3554.         *y += window->borderSize;
  3555.     } 
  3556.     *x += window->rect.x;
  3557.     *y += window->rect.y;
  3558. }
  3559.  
  3560. void Rect_ToWindowCoords(rectDef_t *rect, windowDef_t *window) {
  3561.     ToWindowCoords(&rect->x, &rect->y, window);
  3562. }
  3563.  
  3564. void Item_SetTextExtents(itemDef_t *item, int *width, int *height, const char *text) 
  3565. {
  3566.     const char *textPtr = (text) ? text : item->text;
  3567.  
  3568.     if (textPtr == NULL ) {
  3569.         return;
  3570.     }
  3571.  
  3572.     *width = item->textRect.w;
  3573.     *height = item->textRect.h;
  3574.  
  3575.     // keeps us from computing the widths and heights more than once
  3576.     if (*width == 0 || (item->type == ITEM_TYPE_OWNERDRAW && item->textalignment == ITEM_ALIGN_CENTER)) {
  3577.         int originalWidth = DC->getTextWidth(textPtr, item->textFont, item->textscale, 0);
  3578.  
  3579.         if (item->type == ITEM_TYPE_OWNERDRAW && (item->textalignment == ITEM_ALIGN_CENTER || item->textalignment == ITEM_ALIGN_RIGHT)) {
  3580.             originalWidth += DC->ownerDrawWidth(item->window.ownerDraw, item->textscale, item->textFont );
  3581.         } else if ((item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_PASSWORDFIELD) && item->textalignment == ITEM_ALIGN_CENTER && item->cvar) {
  3582.             char buff[256];
  3583.             DC->getCVarString(item->cvar, buff, 256);
  3584.             originalWidth += DC->getTextWidth(buff, item->textFont, item->textscale, 0);
  3585.         }
  3586.  
  3587.         *width = DC->getTextWidth(textPtr, item->textFont, item->textscale, 0 );
  3588.         *height = DC->getTextHeight(textPtr, item->textFont, item->textscale, 0 );
  3589.         item->textRect.w = *width;
  3590.         item->textRect.h = *height;
  3591.         item->textRect.x = item->textalignx;
  3592.         item->textRect.y = item->textaligny;
  3593.         if (item->textalignment == ITEM_ALIGN_RIGHT) {
  3594.             item->textRect.x = item->textalignx - originalWidth;
  3595.         } else if (item->textalignment == ITEM_ALIGN_CENTER) {
  3596.             item->textRect.x = item->textalignx - originalWidth / 2;
  3597.         }
  3598.  
  3599.         ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
  3600.     }
  3601. }
  3602.  
  3603. void Item_TextColor(itemDef_t *item, vec4_t *newColor) {
  3604.     vec4_t lowLight;
  3605.     menuDef_t *parent = (menuDef_t*)item->parent;
  3606.  
  3607.     Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
  3608.  
  3609. /* no blinking for now
  3610.     if (item->window.flags & WINDOW_HASFOCUS) {
  3611.         lowLight[0] = 0.8 * parent->focusColor[0]; 
  3612.         lowLight[1] = 0.8 * parent->focusColor[1]; 
  3613.         lowLight[2] = 0.8 * parent->focusColor[2]; 
  3614.         lowLight[3] = 0.8 * parent->focusColor[3]; 
  3615.         LerpColor(parent->focusColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  3616.     } else 
  3617. */
  3618.     if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) {
  3619.         lowLight[0] = 0.8 * item->window.foreColor[0]; 
  3620.         lowLight[1] = 0.8 * item->window.foreColor[1]; 
  3621.         lowLight[2] = 0.8 * item->window.foreColor[2]; 
  3622.         lowLight[3] = 0.8 * item->window.foreColor[3]; 
  3623.         LerpColor(item->window.foreColor,lowLight,*newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  3624.     } else {
  3625.         memcpy(newColor, &item->window.foreColor, sizeof(vec4_t));
  3626.         // items can be enabled and disabled based on cvars
  3627.     }
  3628.  
  3629.     if ( item->window.flags & WINDOW_DISABLED )
  3630.     {
  3631.         memcpy(newColor, &parent->disableColor, sizeof(vec4_t));
  3632.     }
  3633.     else if (item->enableCvar && *item->enableCvar && item->cvarTest && *item->cvarTest) 
  3634.     {
  3635.         if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) 
  3636.         {
  3637.             memcpy(newColor, &parent->disableColor, sizeof(vec4_t));
  3638.         }
  3639.     }
  3640. }
  3641.  
  3642. void Item_Text_AutoWrapped_Paint(itemDef_t *item) 
  3643. {
  3644.     char        text[1024];
  3645.     char        buff[1024];
  3646.     const char*    p;
  3647.     const char*    textPtr;
  3648.     const char*    newLinePtr;
  3649.     int            width;
  3650.     int            height;
  3651.     int            len;
  3652.     int            textWidth;
  3653.     int            newLine;
  3654.     int            newLineWidth;
  3655.     float        y;
  3656.     vec4_t        color;
  3657.  
  3658.     if (item->text == NULL) 
  3659.     {
  3660.         if (item->cvar == NULL) 
  3661.         {
  3662.             return;
  3663.         }
  3664.         else 
  3665.         {
  3666.             DC->getCVarString(item->cvar, text, sizeof(text));
  3667.             textPtr = text;
  3668.         }
  3669.     }
  3670.     else 
  3671.     {
  3672.         textPtr = item->text;
  3673.     }
  3674.  
  3675.     if (*textPtr == '\0') 
  3676.     {
  3677.         return;
  3678.     }
  3679.  
  3680.     Item_TextColor(item, &color);
  3681.     Item_SetTextExtents(item, &width, &height, textPtr);
  3682.  
  3683.     y = item->textaligny;
  3684.     len = 0;
  3685.     buff[0] = '\0';
  3686.     textWidth = 0;
  3687.     newLine = 0;
  3688.     newLinePtr = NULL;
  3689.     newLineWidth = 0;
  3690.     p = textPtr;
  3691.     while (p) 
  3692.     {
  3693.         if (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\0') 
  3694.         {
  3695.             newLine = len;
  3696.             newLinePtr = p+1;
  3697.             newLineWidth = textWidth;
  3698.         }
  3699.  
  3700.         textWidth = DC->getTextWidth(buff, item->textFont, item->textscale, 0);
  3701.         if ( (newLine && textWidth > item->window.rect.w - item->textalignx * 2) || *p == '\n' || *p == '\0') 
  3702.         {
  3703.             if (len) 
  3704.             {
  3705.                 if (item->textalignment == ITEM_ALIGN_LEFT) 
  3706.                 {
  3707.                     item->textRect.x = item->textalignx;
  3708.                 } 
  3709.                 else if (item->textalignment == ITEM_ALIGN_RIGHT) 
  3710.                 {
  3711.                     item->textRect.x = item->textalignx - newLineWidth;
  3712.                 } 
  3713.                 else if (item->textalignment == ITEM_ALIGN_CENTER) 
  3714.                 {
  3715.                     item->textRect.x = item->textalignx - newLineWidth / 2;
  3716.                 }
  3717.                 item->textRect.y = y;
  3718.                 ToWindowCoords(&item->textRect.x, &item->textRect.y, &item->window);
  3719.                 //
  3720.                 buff[newLine] = '\0';
  3721.                 DC->drawText(item->textRect.x, item->textRect.y, item->textFont, item->textscale, color, buff, 0, 0 );
  3722.             }
  3723.             
  3724.             if (*p == '\0') 
  3725.             {
  3726.                 break;
  3727.             }
  3728.             //
  3729.             y += height + 5;
  3730.             p = newLinePtr;
  3731.             len = 0;
  3732.             newLine = 0;
  3733.             newLineWidth = 0;
  3734.             continue;
  3735.         }
  3736.         buff[len++] = *p++;
  3737.         buff[len] = '\0';
  3738.     }
  3739. }
  3740.  
  3741. void Item_Text_Wrapped_Paint(itemDef_t *item) {
  3742.     char text[1024];
  3743.     const char *p, *start, *textPtr;
  3744.     char buff[1024];
  3745.     int width, height;
  3746.     float x, y;
  3747.     vec4_t color;
  3748.  
  3749.     // now paint the text and/or any optional images
  3750.     // default to left
  3751.  
  3752.     if (item->text == NULL) {
  3753.         if (item->cvar == NULL) {
  3754.             return;
  3755.         }
  3756.         else {
  3757.             DC->getCVarString(item->cvar, text, sizeof(text));
  3758.             textPtr = text;
  3759.         }
  3760.     }
  3761.     else {
  3762.         textPtr = item->text;
  3763.     }
  3764.     if (*textPtr == '\0') {
  3765.         return;
  3766.     }
  3767.  
  3768.     Item_TextColor(item, &color);
  3769.     Item_SetTextExtents(item, &width, &height, textPtr);
  3770.  
  3771.     x = item->textRect.x;
  3772.     y = item->textRect.y;
  3773.     start = textPtr;
  3774.     p = strchr(textPtr, '\r');
  3775.     while (p && *p) {
  3776.         strncpy(buff, start, p-start+1);
  3777.         buff[p-start] = '\0';
  3778.         DC->drawText(x, y, item->textFont, item->textscale, color, buff, 0, 0 );
  3779.         y += height + 5;
  3780.         start += p - start + 1;
  3781.         p = strchr(p+1, '\r');
  3782.     }
  3783.     DC->drawText(x, y, item->textFont, item->textscale, color, start, 0, 0 );
  3784. }
  3785.  
  3786. void Item_Text_Paint(itemDef_t *item) {
  3787.     char text[1024];
  3788.     const char *textPtr;
  3789.     int height, width;
  3790.     vec4_t color;
  3791.     int        dFlags = 0;
  3792.  
  3793.     if (item->window.flags & WINDOW_WRAPPED) {
  3794.         Item_Text_Wrapped_Paint(item);
  3795.         return;
  3796.     }
  3797.     if (item->window.flags & WINDOW_AUTOWRAPPED) {
  3798.         Item_Text_AutoWrapped_Paint(item);
  3799.         return;
  3800.     }
  3801.  
  3802.     if (item->text == NULL || !*item->text ) 
  3803.     {
  3804.         if (item->cvar == NULL) 
  3805.         {
  3806.             return;
  3807.         }
  3808.         else 
  3809.         {
  3810.             DC->getCVarString(item->cvar, text, sizeof(text));
  3811.             textPtr = text;
  3812.             
  3813.             item->textRect.w = 0;
  3814.             item->textRect.h = 0;
  3815.         }
  3816.     }
  3817.     else 
  3818.     {
  3819.         textPtr = item->text;
  3820.     }
  3821.  
  3822.     // this needs to go here as it sets extents for cvar types as well
  3823.     Item_SetTextExtents(item, &width, &height, textPtr);
  3824.  
  3825.     if (*textPtr == '\0') {
  3826.         return;
  3827.     }
  3828.  
  3829.  
  3830.     Item_TextColor(item, &color);
  3831.  
  3832.     //FIXME: this is a fucking mess
  3833. /*
  3834.     adjust = 0;
  3835.     if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
  3836.         adjust = 0.5;
  3837.     }
  3838.  
  3839.     if (item->textStyle == ITEM_TEXTSTYLE_SHADOWED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
  3840.         Fade(&item->window.flags, &DC->Assets.shadowColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
  3841.         DC->drawText(item->textRect.x + DC->Assets.shadowX, item->textRect.y + DC->Assets.shadowY, item->textscale, DC->Assets.shadowColor, textPtr, adjust);
  3842.     }
  3843. */
  3844.  
  3845.     if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED )
  3846.     {
  3847.         dFlags |= DT_OUTLINE;
  3848.     }
  3849.  
  3850. //    if (item->textStyle == ITEM_TEXTSTYLE_OUTLINED || item->textStyle == ITEM_TEXTSTYLE_OUTLINESHADOWED) {
  3851. //        Fade(&item->window.flags, &item->window.outlineColor[3], DC->Assets.fadeClamp, &item->window.nextTime, DC->Assets.fadeCycle, qfalse);
  3852. //        /*
  3853. //        Text_Paint(item->textRect.x-1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
  3854. //        Text_Paint(item->textRect.x, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
  3855. //        Text_Paint(item->textRect.x+1, item->textRect.y-1, item->textscale, item->window.foreColor, textPtr, adjust);
  3856. //        Text_Paint(item->textRect.x-1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
  3857. //        Text_Paint(item->textRect.x+1, item->textRect.y, item->textscale, item->window.foreColor, textPtr, adjust);
  3858. //        Text_Paint(item->textRect.x-1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
  3859. //        Text_Paint(item->textRect.x, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
  3860. //        Text_Paint(item->textRect.x+1, item->textRect.y+1, item->textscale, item->window.foreColor, textPtr, adjust);
  3861. //        */
  3862. //        DC->drawText(item->textRect.x - 1, item->textRect.y + 1, item->textscale * 1.02, item->window.outlineColor, textPtr, adjust);
  3863. //    }
  3864.  
  3865.     DC->drawText(item->textRect.x, item->textRect.y, item->textFont, item->textscale, color, textPtr, 0, dFlags );
  3866.  
  3867.  
  3868.     if (item->text2)    // Is there a second line of text?
  3869.     {
  3870.         Item_TextColor(item, &color);
  3871.         DC->drawText(item->textRect.x + item->text2alignx, item->textRect.y + item->text2aligny, item->textFont, item->textscale, color, item->text2, 0, dFlags );
  3872.     }
  3873.  
  3874. }
  3875.  
  3876.  
  3877.  
  3878. //float            trap_Cvar_VariableValue( const char *var_name );
  3879. //void            trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize );
  3880.  
  3881. void Item_TextField_Paint(itemDef_t *item) 
  3882. {
  3883.     char            buff[1024];
  3884.     vec4_t            newColor;
  3885.     int                offset;
  3886.     menuDef_t        *parent = (menuDef_t*)item->parent;
  3887.     editFieldDef_t    *editPtr = (editFieldDef_t*)item->typeData;
  3888.  
  3889.     buff[0] = '\0';
  3890.  
  3891.     if (item->cvar) 
  3892.     {
  3893.         DC->getCVarString(item->cvar, buff, sizeof(buff));
  3894.     } 
  3895.  
  3896.     if ( item->text && *item->text )
  3897.     {
  3898.         Item_Text_Paint(item);
  3899.     }
  3900.     else
  3901.     {
  3902.         item->textRect.w = 0;
  3903.         item->textRect.h = 0;
  3904.         item->textRect.x = item->window.rect.x + item->textalignx;
  3905.         item->textRect.y = item->window.rect.y + item->textaligny;
  3906.     }
  3907.  
  3908.     // If this is a password field then we need to render *'s instead of the real chars
  3909.     if ( item->type == ITEM_TYPE_PASSWORDFIELD )
  3910.     {
  3911.         // Fill the string with stars
  3912.         for ( offset = 0; buff[offset]; offset++ )
  3913.             buff[offset] = '*';
  3914.     }
  3915.  
  3916.     parent = (menuDef_t*)item->parent;
  3917.  
  3918. /* No more focus blinking
  3919.     if (item->window.flags & WINDOW_HASFOCUS) {
  3920.         lowLight[0] = 0.8 * parent->focusColor[0]; 
  3921.         lowLight[1] = 0.8 * parent->focusColor[1]; 
  3922.         lowLight[2] = 0.8 * parent->focusColor[2]; 
  3923.         lowLight[3] = 0.8 * parent->focusColor[3]; 
  3924.         LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  3925.     } else {
  3926.         memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  3927.     }
  3928. */
  3929.     memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  3930.  
  3931.     offset = (item->text && *item->text) ? 8 : 0;
  3932.  
  3933.     if ((item->window.flags & WINDOW_HASFOCUS) && g_editingField) 
  3934.     {
  3935.         char cursor = DC->getOverstrikeMode() ? '_' : '|';
  3936.         DC->drawTextWithCursor(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textFont, item->textscale, newColor, buff + editPtr->paintOffset, editPtr->maxPaintChars, 0, item->cursorPos - editPtr->paintOffset, cursor );
  3937.     } 
  3938.     else 
  3939.     {
  3940.         DC->drawText(item->textRect.x + item->textRect.w + offset, item->textRect.y, item->textFont, item->textscale, newColor, buff + editPtr->paintOffset, editPtr->maxPaintChars, 0 );
  3941.     }
  3942. }
  3943.  
  3944. void Item_YesNo_Paint(itemDef_t *item) 
  3945. {
  3946.     vec4_t    newColor;
  3947.     float    value;
  3948.  
  3949.     value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
  3950.  
  3951.     memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  3952.  
  3953.     if (item->text) 
  3954.     {
  3955.         Item_Text_Paint(item);
  3956.         DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textFont, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0);
  3957.     } 
  3958.     else 
  3959.     {
  3960.         DC->drawText(item->textRect.x, item->textRect.y, item->textFont, item->textscale, newColor, (value != 0) ? "Yes" : "No", 0, 0);
  3961.     }
  3962. }
  3963.  
  3964. void Item_Multi_Paint(itemDef_t *item) 
  3965. {
  3966.     vec4_t newColor;
  3967.     const char *text = "";
  3968.  
  3969.      memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  3970.  
  3971.     text = Item_Multi_Setting(item);
  3972.  
  3973.     if (item->text) 
  3974.     {
  3975.         Item_Text_Paint(item);
  3976.         DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textFont, item->textscale, newColor, text, 0, 0);
  3977.     } 
  3978.     else 
  3979.     {
  3980.         DC->drawText(item->textRect.x, item->textRect.y, item->textFont, item->textscale, newColor, text, 0, 0 );
  3981.     }
  3982. }
  3983.  
  3984.  
  3985. typedef struct {
  3986.     char    *command;
  3987.     int        id;
  3988.     int        defaultbind1;
  3989.     int        defaultbind2;
  3990.     int        bind1;
  3991.     int        bind2;
  3992. } bind_t;
  3993.  
  3994. typedef struct
  3995. {
  3996.     char*    name;
  3997.     float    defaultvalue;
  3998.     float    value;    
  3999. } configcvar_t;
  4000.  
  4001.  
  4002. static bind_t g_bindings[] = 
  4003. {
  4004.     {"+scores",             K_TAB,                -1,        -1, -1},
  4005.     {"+speed",              K_SHIFT,            -1,        -1,    -1},
  4006.     {"+forward",          K_UPARROW,            -1,        -1, -1},
  4007.     {"+back",              K_DOWNARROW,        -1,        -1, -1},
  4008.     {"+moveleft",         ',',                -1,        -1, -1},
  4009.     {"+moveright",          '.',                -1,        -1, -1},
  4010.     {"+moveup",             K_SPACE,            -1,        -1, -1},
  4011.     {"+movedown",         'c',                -1,        -1, -1},
  4012.     {"+left",              K_LEFTARROW,        -1,        -1, -1},
  4013.     {"+right",              K_RIGHTARROW,        -1,        -1, -1},
  4014.     {"+strafe",          K_ALT,                -1,        -1, -1},
  4015.     {"+lookup",          K_PGDN,            -1,        -1, -1},
  4016.     {"+lookdown",          K_DEL,                -1,        -1, -1},
  4017.     {"+mlook",              '/',                -1,        -1, -1},
  4018.     {"centerview",         K_END,                -1,        -1, -1},
  4019.     {"weapon 1",         '1',                -1,        -1, -1},
  4020.     {"weapon 2",         '2',                -1,        -1, -1},
  4021.     {"weapon 3",         '3',                -1,        -1, -1},
  4022.     {"weapon 4",         '4',                -1,        -1, -1},
  4023.     {"weapon 5",         '5',                -1,        -1, -1},
  4024.     {"weapon 6",         '6',                -1,        -1, -1},
  4025.     {"weapon 7",         '7',                -1,        -1, -1},
  4026.     {"weapon 8",         '8',                -1,        -1, -1},
  4027.     {"weapon 9",         '9',                -1,        -1, -1},
  4028.     {"weapon 10",         '0',                -1,        -1, -1},
  4029.     {"weapon 11",         -1,                -1,        -1, -1},
  4030.     {"weapon 12",         -1,                -1,        -1, -1},
  4031.     {"weapon 13",         -1,                -1,        -1, -1},
  4032.     {"+attack",          K_CTRL,            -1,        -1, -1},
  4033.     {"+altattack",         K_MOUSE2,            -1,        -1,    -1},
  4034.     {"weapprev",         '[',                -1,        -1, -1},
  4035.     {"weapnext",          ']',                -1,        -1, -1},
  4036.     {"weaplast",          -1,                -1,        -1, -1},
  4037.     {"messagemode",        't',                -1,        -1, -1},
  4038.     {"messagemode2",    'y',                -1,        -1, -1},
  4039.     {"messagemode3",    -1,                    -1,        -1, -1},
  4040.     {"messagemode4",    -1,                    -1,        -1, -1},
  4041.     {"+reload",            K_MOUSE3,            -1,        -1,    -1},
  4042.     {"+zoomin",            '=',                -1,        -1,    -1},
  4043.     {"+zoomout",        '-',                -1,        -1,    -1},
  4044.     {"+firemode",        'r',                -1,        -1,    -1},
  4045.     {"ui_objectives",    'o',                -1,        -1, -1},
  4046.     {"ui_radio",        'u',                -1,        -1,    -1},
  4047.     {"ui_outfitting",    'b',                -1,        -1, -1},
  4048.     {"ui_team",            'n',                -1,        -1, -1},
  4049.     {"+automap",        'm',                -1,        -1,    -1},
  4050.     {"+lean",            -1,                    -1,        -1,    -1},
  4051.     {"+leanleft",        'q',                -1,        -1,    -1},
  4052.     {"+leanright",        'e',                -1,        -1,    -1},
  4053.     {"+autorun",        K_KP_NUMLOCK,        -1,        -1,    -1},
  4054.     {"drop",            'f',                -1,        -1, -1},
  4055.     {"+goggles",        K_ENTER,            -1,        -1,    -1},
  4056.     {"vote yes",        K_F1,                -1,        -1,    -1},
  4057.     {"vote no",            K_F2,                -1,        -1,    -1},
  4058.     {"+use",            'x',                -1,        -1,    -1},
  4059.     {"dropitem",        -1,                    -1,        -1,    -1},
  4060. };
  4061.  
  4062.  
  4063. static const int g_bindCount = sizeof(g_bindings) / sizeof(bind_t);
  4064.  
  4065. /*
  4066. =================
  4067. Controls_GetKeyAssignment
  4068. =================
  4069. */
  4070. static void Controls_GetKeyAssignment (char *command, int *twokeys)
  4071. {
  4072.     int        count;
  4073.     int        j;
  4074.     char    b[256];
  4075.  
  4076.     twokeys[0] = twokeys[1] = -1;
  4077.     count = 0;
  4078.  
  4079.     for ( j = 0; j < 256; j++ )
  4080.     {
  4081.         DC->getBindingBuf( j, b, 256 );
  4082.         if ( *b == 0 ) {
  4083.             continue;
  4084.         }
  4085.         if ( !Q_stricmp( b, command ) ) {
  4086.             twokeys[count] = j;
  4087.             count++;
  4088.             if (count == 2) {
  4089.                 break;
  4090.             }
  4091.         }
  4092.     }
  4093. }
  4094.  
  4095. /*
  4096. =================
  4097. Controls_GetConfig
  4098. =================
  4099. */
  4100. void Controls_GetConfig( void )
  4101. {
  4102.     int        i;
  4103.     int        twokeys[2];
  4104.  
  4105.     // iterate each command, get its numeric binding
  4106.     for (i=0; i < g_bindCount; i++)
  4107.     {
  4108.  
  4109.         Controls_GetKeyAssignment(g_bindings[i].command, twokeys);
  4110.  
  4111.         g_bindings[i].bind1 = twokeys[0];
  4112.         g_bindings[i].bind2 = twokeys[1];
  4113.     }
  4114. }
  4115.  
  4116. /*
  4117. =================
  4118. Controls_SetConfig
  4119. =================
  4120. */
  4121. void Controls_SetConfig(qboolean restart)
  4122. {
  4123.     int        i;
  4124.  
  4125.     // iterate each command, get its numeric binding
  4126.     for (i=0; i < g_bindCount; i++)
  4127.     {
  4128.  
  4129.         if (g_bindings[i].bind1 != -1)
  4130.         {    
  4131.             DC->setBinding( g_bindings[i].bind1, g_bindings[i].command );
  4132.  
  4133.             if (g_bindings[i].bind2 != -1)
  4134.                 DC->setBinding( g_bindings[i].bind2, g_bindings[i].command );
  4135.         }
  4136.     }
  4137.  
  4138.     //if ( s_controls.invertmouse.curvalue )
  4139.     //    DC->setCVar("m_pitch", va("%f),-fabs( DC->getCVarValue( "m_pitch" ) ) );
  4140.     //else
  4141.     //    trap_Cvar_SetValue( "m_pitch", fabs( trap_Cvar_VariableValue( "m_pitch" ) ) );
  4142.  
  4143.     //trap_Cvar_SetValue( "m_filter", s_controls.smoothmouse.curvalue );
  4144.     //trap_Cvar_SetValue( "cl_run", s_controls.alwaysrun.curvalue );
  4145.     //trap_Cvar_SetValue( "cg_autoswitch", s_controls.autoswitch.curvalue );
  4146.     //trap_Cvar_SetValue( "sensitivity", s_controls.sensitivity.curvalue );
  4147.     //trap_Cvar_SetValue( "in_joystick", s_controls.joyenable.curvalue );
  4148.     //trap_Cvar_SetValue( "joy_threshold", s_controls.joythreshold.curvalue );
  4149.     //trap_Cvar_SetValue( "cl_freelook", s_controls.freelook.curvalue );
  4150.     if (restart)
  4151.     {
  4152.         DC->executeText(EXEC_APPEND, "in_restart\n");
  4153.     }
  4154.  
  4155. }
  4156.  
  4157. /*
  4158. =================
  4159. Controls_SetDefaults
  4160. =================
  4161. */
  4162. void Controls_SetDefaults( void )
  4163. {
  4164.     int    i;
  4165.  
  4166.     // iterate each command, set its default binding
  4167.   for (i=0; i < g_bindCount; i++)
  4168.     {
  4169.         g_bindings[i].bind1 = g_bindings[i].defaultbind1;
  4170.         g_bindings[i].bind2 = g_bindings[i].defaultbind2;
  4171.     }
  4172.  
  4173.     //s_controls.invertmouse.curvalue  = Controls_GetCvarDefault( "m_pitch" ) < 0;
  4174.     //s_controls.smoothmouse.curvalue  = Controls_GetCvarDefault( "m_filter" );
  4175.     //s_controls.alwaysrun.curvalue    = Controls_GetCvarDefault( "cl_run" );
  4176.     //s_controls.autoswitch.curvalue   = Controls_GetCvarDefault( "cg_autoswitch" );
  4177.     //s_controls.sensitivity.curvalue  = Controls_GetCvarDefault( "sensitivity" );
  4178.     //s_controls.joyenable.curvalue    = Controls_GetCvarDefault( "in_joystick" );
  4179.     //s_controls.joythreshold.curvalue = Controls_GetCvarDefault( "joy_threshold" );
  4180.     //s_controls.freelook.curvalue     = Controls_GetCvarDefault( "cl_freelook" );
  4181. }
  4182.  
  4183. int BindingIDFromName(const char *name) {
  4184.     int i;
  4185.   for (i=0; i < g_bindCount; i++)
  4186.     {
  4187.         if (Q_stricmp(name, g_bindings[i].command) == 0) {
  4188.             return i;
  4189.         }
  4190.     }
  4191.     return -1;
  4192. }
  4193.  
  4194. char g_nameBind1[32];
  4195. char g_nameBind2[32];
  4196.  
  4197. void BindingFromName(const char *cvar) {
  4198.     int    i, b1, b2;
  4199.  
  4200.     // iterate each command, set its default binding
  4201.     for (i=0; i < g_bindCount; i++)
  4202.     {
  4203.         if (Q_stricmp(cvar, g_bindings[i].command) == 0) {
  4204.             b1 = g_bindings[i].bind1;
  4205.             if (b1 == -1) {
  4206.                 break;
  4207.             }
  4208.                 DC->keynumToStringBuf( b1, g_nameBind1, 32 );
  4209.                 Q_strupr(g_nameBind1);
  4210.  
  4211.                 b2 = g_bindings[i].bind2;
  4212.                 if (b2 != -1)
  4213.                 {
  4214.                     DC->keynumToStringBuf( b2, g_nameBind2, 32 );
  4215.                     Q_strupr(g_nameBind2);
  4216.                     strcat( g_nameBind1, " or " );
  4217.                     strcat( g_nameBind1, g_nameBind2 );
  4218.                 }
  4219.             return;
  4220.         }
  4221.     }
  4222.     strcpy(g_nameBind1, "???");
  4223. }
  4224.  
  4225. void Item_Slider_Paint(itemDef_t *item) 
  4226. {
  4227.     vec4_t newColor;
  4228.     float x, y, value;
  4229.  
  4230.     value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
  4231.  
  4232.     memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  4233.  
  4234.     y = item->window.rect.y;
  4235.     if (item->text && *item->text ) 
  4236.     {
  4237.         Item_Text_Paint(item);
  4238.         x = item->textRect.x + item->textRect.w + 8;
  4239.     } 
  4240.     else 
  4241.     {
  4242.         x = item->window.rect.x;
  4243.     }
  4244.  
  4245.     DC->setColor(newColor);
  4246.     DC->drawHandlePic( x, y, SLIDER_WIDTH, SLIDER_HEIGHT, DC->Assets.sliderBar );
  4247.  
  4248.     x = Item_Slider_ThumbPosition(item);
  4249.     DC->drawHandlePic( x, y, SLIDER_THUMB_WIDTH, SLIDER_THUMB_HEIGHT, DC->Assets.sliderThumb );
  4250.  
  4251.     DC->setColor ( NULL );
  4252. }
  4253.  
  4254. void Item_Bind_Paint(itemDef_t *item) {
  4255.     vec4_t newColor, lowLight;
  4256.     float value;
  4257.     int maxChars = 0;
  4258.     menuDef_t *parent = (menuDef_t*)item->parent;
  4259.     editFieldDef_t *editPtr = (editFieldDef_t*)item->typeData;
  4260.     if (editPtr) {
  4261.         maxChars = editPtr->maxPaintChars;
  4262.     }
  4263.  
  4264.     value = (item->cvar) ? DC->getCVarValue(item->cvar) : 0;
  4265.  
  4266.     if (item->window.flags & WINDOW_HASFOCUS) {
  4267.         if (g_bindItem == item && Display_KeyBindPending ( ) ) {
  4268.             lowLight[0] = 0.8f * 1.0f;
  4269.             lowLight[1] = 0.8f * 0.0f;
  4270.             lowLight[2] = 0.8f * 0.0f;
  4271.             lowLight[3] = 0.8f * 1.0f;
  4272.  
  4273.             LerpColor(parent->focusColor,lowLight,newColor,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  4274.         } else {
  4275.  
  4276.             /* no more blinking
  4277.             lowLight[0] = 0.8f * parent->focusColor[0]; 
  4278.             lowLight[1] = 0.8f * parent->focusColor[1]; 
  4279.             lowLight[2] = 0.8f * parent->focusColor[2]; 
  4280.             lowLight[3] = 0.8f * parent->focusColor[3]; 
  4281.             */
  4282.  
  4283.             memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  4284.         }
  4285.     } else {
  4286.         memcpy(&newColor, &item->window.foreColor, sizeof(vec4_t));
  4287.     }
  4288.  
  4289.     if (item->text) {
  4290.         Item_Text_Paint(item);
  4291.         BindingFromName(item->cvar);
  4292.         DC->drawText(item->textRect.x + item->textRect.w + 8, item->textRect.y, item->textFont, item->textscale, newColor, g_nameBind1, maxChars, 0 );
  4293.     } else {
  4294.         DC->drawText(item->textRect.x, item->textRect.y, item->textFont, item->textscale, newColor, (value != 0) ? "FIXME" : "FIXME", maxChars, 0 );
  4295.     }
  4296. }
  4297.  
  4298. qboolean Display_KeyBindPending() {
  4299.     return g_waitingForKey;
  4300. }
  4301.  
  4302. qboolean Item_Bind_HandleKey(itemDef_t *item, int key, qboolean down) {
  4303.     int            id;
  4304.     int            i;
  4305.  
  4306.     if (Rect_ContainsPoint(&item->window.rect, DC->cursorx, DC->cursory) && !g_waitingForKey)
  4307.     {
  4308.         if (down)
  4309.         {
  4310.             if (key == K_MOUSE1 || key == K_ENTER) 
  4311.             {
  4312.                 g_waitingForKey = qtrue;
  4313.                 g_bindItem = item;
  4314.                 return qtrue;
  4315.             }
  4316.             else if (key == K_BACKSPACE || key == K_DEL)
  4317.             {
  4318.                 id = BindingIDFromName(item->cvar);
  4319.                 if (id != -1) 
  4320.                 {
  4321.                     if ( g_bindings[id].bind1 != -1 )
  4322.                     {
  4323.                         DC->setBinding ( g_bindings[id].bind1, "" );
  4324.                     }
  4325.                     
  4326.                     if ( g_bindings[id].bind2 != -1 )
  4327.                     {
  4328.                         DC->setBinding ( g_bindings[id].bind2, "" );
  4329.                     }
  4330.  
  4331.                     g_bindings[id].bind1 = -1;
  4332.                     g_bindings[id].bind2 = -1;
  4333.                 }
  4334.                 Controls_SetConfig(qfalse);
  4335.                 g_waitingForKey = qfalse;
  4336.                 g_bindItem = NULL;
  4337.                 return qtrue;
  4338.             }
  4339.         }
  4340.         return qfalse;
  4341.     }
  4342.     else
  4343.     {
  4344.         if (!g_waitingForKey || g_bindItem == NULL) {
  4345. //            return qtrue;
  4346.             return qfalse;
  4347.         }
  4348.  
  4349.         if (key & K_CHAR_FLAG) {
  4350.             return qtrue;
  4351.         }
  4352.  
  4353.         switch (key)
  4354.         {
  4355.             case K_ESCAPE:
  4356.                 g_waitingForKey = qfalse;
  4357.                 return qtrue;
  4358.     
  4359.             case '`':
  4360.                 return qtrue;
  4361.         }
  4362.     }
  4363.  
  4364.     if (key != -1)
  4365.     {
  4366.  
  4367.         for (i=0; i < g_bindCount; i++)
  4368.         {
  4369.  
  4370.             if (g_bindings[i].bind2 == key) {
  4371.                 g_bindings[i].bind2 = -1;
  4372.             }
  4373.  
  4374.             if (g_bindings[i].bind1 == key)
  4375.             {
  4376.                 g_bindings[i].bind1 = g_bindings[i].bind2;
  4377.                 g_bindings[i].bind2 = -1;
  4378.             }
  4379.         }
  4380.     }
  4381.  
  4382.  
  4383.     id = BindingIDFromName(item->cvar);
  4384.  
  4385.     if (id != -1) {
  4386.         if (key == -1) {
  4387.             if( g_bindings[id].bind1 != -1 ) {
  4388.                 DC->setBinding( g_bindings[id].bind1, "" );
  4389.                 g_bindings[id].bind1 = -1;
  4390.             }
  4391.             if( g_bindings[id].bind2 != -1 ) {
  4392.                 DC->setBinding( g_bindings[id].bind2, "" );
  4393.                 g_bindings[id].bind2 = -1;
  4394.             }
  4395.         }
  4396.         else if (g_bindings[id].bind1 == -1) {
  4397.             g_bindings[id].bind1 = key;
  4398.         }
  4399.         else if (g_bindings[id].bind1 != key && g_bindings[id].bind2 == -1) {
  4400.             g_bindings[id].bind2 = key;
  4401.         }
  4402.         else {
  4403.             DC->setBinding( g_bindings[id].bind1, "" );
  4404.             DC->setBinding( g_bindings[id].bind2, "" );
  4405.             g_bindings[id].bind1 = key;
  4406.             g_bindings[id].bind2 = -1;
  4407.         }                        
  4408.     }
  4409.  
  4410.     Controls_SetConfig(qfalse);    
  4411.     g_waitingForKey = qfalse;
  4412.  
  4413.     return qtrue;
  4414. }
  4415.  
  4416.  
  4417.  
  4418. void AdjustFrom640(float *x, float *y, float *w, float *h) {
  4419.     //*x = *x * DC->scale + DC->bias;
  4420.     *x *= DC->xscale;
  4421.     *y *= DC->yscale;
  4422.     *w *= DC->xscale;
  4423.     *h *= DC->yscale;
  4424. }
  4425.  
  4426. void Item_Model_Paint(itemDef_t *item) {
  4427.     float x, y, w, h;
  4428.     refdef_t refdef;
  4429.     refEntity_t        ent;
  4430.     vec3_t            mins, maxs, origin;
  4431.     vec3_t            angles;
  4432.     modelDef_t *modelPtr = (modelDef_t*)item->typeData;
  4433.  
  4434.     if (modelPtr == NULL) {
  4435.         return;
  4436.     }
  4437.  
  4438.     // setup the refdef
  4439.     memset( &refdef, 0, sizeof( refdef ) );
  4440.     refdef.rdflags = RDF_NOWORLDMODEL;
  4441.     AxisClear( refdef.viewaxis );
  4442.     x = item->window.rect.x+1;
  4443.     y = item->window.rect.y+1;
  4444.     w = item->window.rect.w-2;
  4445.     h = item->window.rect.h-2;
  4446.  
  4447.     AdjustFrom640( &x, &y, &w, &h );
  4448.  
  4449.     refdef.x = x;
  4450.     refdef.y = y;
  4451.     refdef.width = w;
  4452.     refdef.height = h;
  4453.  
  4454.     DC->modelBounds( item->asset, mins, maxs );
  4455.  
  4456.     origin[2] = -0.5 * ( mins[2] + maxs[2] );
  4457.     origin[1] = 0.5 * ( mins[1] + maxs[1] );
  4458.  
  4459.     // calculate distance so the model nearly fills the box
  4460.     if (qtrue) {
  4461.         float len = 0.5 * ( maxs[2] - mins[2] );        
  4462.         origin[0] = len / 0.268;    // len / tan( fov/2 )
  4463.         //origin[0] = len / tan(w/2);
  4464.     } else {
  4465.         origin[0] = item->textscale;
  4466.     }
  4467.     refdef.fov_x = (modelPtr->fov_x) ? modelPtr->fov_x : w;
  4468.     refdef.fov_y = (modelPtr->fov_y) ? modelPtr->fov_y : h;
  4469.  
  4470.     //refdef.fov_x = (int)((float)refdef.width / 640.0f * 90.0f);
  4471.     //xx = refdef.width / tan( refdef.fov_x / 360 * M_PI );
  4472.     //refdef.fov_y = atan2( refdef.height, xx );
  4473.     //refdef.fov_y *= ( 360 / M_PI );
  4474.  
  4475.     DC->clearScene();
  4476.  
  4477.     refdef.time = DC->realTime;
  4478.  
  4479.     // add the model
  4480.  
  4481.     memset( &ent, 0, sizeof(ent) );
  4482.  
  4483.     //adjust = 5.0 * sin( (float)uis.realtime / 500 );
  4484.     //adjust = 360 % (int)((float)uis.realtime / 1000);
  4485.     //VectorSet( angles, 0, 0, 1 );
  4486.  
  4487.     // use item storage to track
  4488.     if (modelPtr->rotationSpeed) {
  4489.         if (DC->realTime > item->window.nextTime) {
  4490.             item->window.nextTime = DC->realTime + modelPtr->rotationSpeed;
  4491.             modelPtr->angle = (int)(modelPtr->angle + 1) % 360;
  4492.         }
  4493.     }
  4494.     VectorSet( angles, 0, modelPtr->angle, 0 );
  4495.     AnglesToAxis( angles, ent.axis );
  4496.  
  4497.     ent.hModel = item->asset;
  4498.     VectorCopy( origin, ent.origin );
  4499.     VectorCopy( origin, ent.lightingOrigin );
  4500.     ent.renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW;
  4501.     VectorCopy( ent.origin, ent.oldorigin );
  4502.  
  4503.     DC->addRefEntityToScene( &ent );
  4504.     DC->renderScene( &refdef );
  4505.  
  4506. }
  4507.  
  4508.  
  4509. void Item_Image_Paint(itemDef_t *item) {
  4510.     if (item == NULL) {
  4511.         return;
  4512.     }
  4513.     DC->drawHandlePic(item->window.rect.x+1, item->window.rect.y+1, item->window.rect.w-2, item->window.rect.h-2, item->asset);
  4514. }
  4515.  
  4516. void Item_TextScroll_Paint(itemDef_t *item) 
  4517. {
  4518.     float x, y, size, count, thumb;
  4519.     int      i;
  4520.     qhandle_t        optionalImage;
  4521.     textScrollDef_t *scrollPtr;
  4522.  
  4523.     scrollPtr = (textScrollDef_t*)item->typeData;
  4524.  
  4525.     if (item->special && !scrollPtr->lineCount )
  4526.     {
  4527.         item->text = (char *) DC->feederItemText(item->special, 0, 0, &optionalImage);
  4528.  
  4529.         scrollPtr->startPos = 0;
  4530.         scrollPtr->endPos = 0;
  4531.  
  4532.         Item_TextScroll_BuildLines ( item );
  4533.     }
  4534.  
  4535.     count = scrollPtr->lineCount;
  4536.  
  4537.     // draw scrollbar to right side of the window
  4538.     x = item->window.rect.x + item->window.rect.w - SCROLLBAR_SIZE - 1;
  4539.     y = item->window.rect.y + 1;
  4540.     DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp);
  4541.     y += SCROLLBAR_SIZE - 1;
  4542.  
  4543.     scrollPtr->endPos = scrollPtr->startPos;
  4544.     size = item->window.rect.h - (SCROLLBAR_SIZE * 2);
  4545.     DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar);
  4546.     y += size - 1;
  4547.     DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown);
  4548.     
  4549.     // thumb
  4550.     thumb = Item_TextScroll_ThumbDrawPosition(item);
  4551.     if (thumb > y - SCROLLBAR_SIZE - 1) 
  4552.     {
  4553.         thumb = y - SCROLLBAR_SIZE - 1;
  4554.     }
  4555.     DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
  4556.  
  4557.     // adjust size for item painting
  4558.     size = item->window.rect.h - 2;
  4559.     x     = item->window.rect.x + 1;
  4560.     y     = item->window.rect.y + 1;
  4561.  
  4562.     for (i = scrollPtr->startPos; i < count; i++) 
  4563.     {
  4564.         char *text;
  4565.  
  4566.         text = scrollPtr->lines[i];
  4567.         if (!text) 
  4568.         {
  4569.             continue;
  4570.         }
  4571.  
  4572.         DC->drawText( 
  4573.             x, 
  4574.             y + item->textaligny, 
  4575.             item->textFont, 
  4576.             item->textscale, 
  4577.             item->window.foreColor, 
  4578.             text, 
  4579.             0, 0 );
  4580.  
  4581.         size -= scrollPtr->lineHeight;
  4582.         if (size < scrollPtr->lineHeight) 
  4583.         {
  4584.             scrollPtr->drawPadding = scrollPtr->lineHeight - size;
  4585.             break;
  4586.         }
  4587.  
  4588.         scrollPtr->endPos++;
  4589.         y += scrollPtr->lineHeight;
  4590.     }
  4591. }
  4592.  
  4593. void Item_ListBox_Paint(itemDef_t *item) 
  4594. {
  4595.     float            x, y, size, count, i, thumb;
  4596.     qhandle_t        image;
  4597.     qhandle_t        optionalImage;
  4598.     listBoxDef_t    *listPtr = (listBoxDef_t*)item->typeData;
  4599.     rectDef_t        rect;
  4600.     const char        *text;
  4601.  
  4602.     rect = item->window.rect;
  4603.  
  4604.     if ( item->type == ITEM_TYPE_COMBOBOX )
  4605.     {
  4606.             // default is vertical if horizontal flag is not here
  4607.         // draw scrollbar to right side of the window
  4608.         x = listPtr->comboRect.x + listPtr->comboRect.w - listPtr->comboRect.h - 1;
  4609.         y = listPtr->comboRect.y;
  4610.         DC->drawHandlePic(x, y, listPtr->comboRect.h, listPtr->comboRect.h, DC->Assets.scrollBarArrowDown);
  4611.         y += listPtr->comboRect.h - 1;
  4612.  
  4613.         // Draw the current text in the combo box
  4614.         x = listPtr->comboRect.x + 4 + item->textalignx;
  4615.         text = DC->feederItemText ( item->special, item->cursorPos, 0, &optionalImage );
  4616.         DC->drawText( x, y + item->textaligny, item->textFont, 
  4617.                       item->textscale, item->window.foreColor, text, 0, 0 );
  4618.  
  4619.         // If the combo box isnt dropped down then enough is rendered
  4620.         if ( !(item->window.flags & WINDOW_DROPPED ) )
  4621.         {
  4622.             return;
  4623.         }
  4624.  
  4625.         DC->drawRect ( rect.x, rect.y + listPtr->elementHeight, rect.w, item->window.border, 1, item->window.borderColor );
  4626.  
  4627.         rect.y += (listPtr->elementHeight + item->window.border);
  4628.         rect.h -= (listPtr->elementHeight + item->window.border);
  4629.     }
  4630.  
  4631.     // the listbox is horizontal or vertical and has a fixed size scroll bar going either direction
  4632.     // elements are enumerated from the DC and either text or image handles are acquired from the DC as well
  4633.     // textscale is used to size the text, textalignx and textaligny are used to size image elements
  4634.     // there is no clipping available so only the last completely visible item is painted
  4635.     count = DC->feederCount(item->special);
  4636.     
  4637.     // default is vertical if horizontal flag is not here
  4638.     if (item->window.flags & WINDOW_HORIZONTAL) 
  4639.     {
  4640.         // draw scrollbar in bottom of the window
  4641.         // bar
  4642.         x = rect.x + 1;
  4643.         y = rect.y + rect.h - SCROLLBAR_SIZE - 1;
  4644.         DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowLeft);
  4645.         x += SCROLLBAR_SIZE - 1;
  4646.         size = rect.w - (SCROLLBAR_SIZE * 2);
  4647.         DC->drawHandlePic(x, y, size+1, SCROLLBAR_SIZE, DC->Assets.scrollBarHoriz);
  4648.         x += size - 1;
  4649.         DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowRight);
  4650.         // thumb
  4651.         thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
  4652.         if (thumb > x - SCROLLBAR_SIZE - 1) {
  4653.             thumb = x - SCROLLBAR_SIZE - 1;
  4654.         }
  4655.         DC->drawHandlePic(thumb, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
  4656.         //
  4657.         listPtr->endPos = listPtr->startPos;
  4658.         size = rect.w - 2;
  4659.         // items
  4660.         // size contains max available space
  4661.         if (listPtr->elementStyle == LISTBOX_IMAGE) {
  4662.             // fit = 0;
  4663.             x = rect.x + 1;
  4664.             y = rect.y + 1;
  4665.             for (i = listPtr->startPos; i < count; i++) {
  4666.                 // always draw at least one
  4667.                 // which may overdraw the box if it is too small for the element
  4668.                 image = DC->feederItemImage(item->special, i);
  4669.                 if (image) {
  4670.                     DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
  4671.                 }
  4672.  
  4673.                 if (i == item->cursorPos) {
  4674.                     DC->drawRect(x, y, listPtr->elementWidth-1, listPtr->elementHeight-1, item->window.borderSize, item->window.outlineColor);
  4675.                 }
  4676.  
  4677.                 size -= listPtr->elementWidth;
  4678.                 if (size < listPtr->elementWidth) {
  4679.                     listPtr->drawPadding = size; //listPtr->elementWidth - size;
  4680.                     break;
  4681.                 }
  4682.                 x += listPtr->elementWidth;
  4683.                 listPtr->endPos++;
  4684.                 // fit++;
  4685.             }
  4686.         } else {
  4687.             //
  4688.         }
  4689.  
  4690.         // Endpos is one past the end
  4691.         listPtr->endPos++;
  4692.     } 
  4693.     else 
  4694.     {
  4695.         DC->setColor ( colorWhite );
  4696.  
  4697.         // draw scrollbar to right side of the window
  4698.         x = rect.x + rect.w - SCROLLBAR_SIZE - 1;
  4699.         y = rect.y + 1;
  4700.         DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowUp);
  4701.         y += SCROLLBAR_SIZE - 1;
  4702.  
  4703.         listPtr->endPos = listPtr->startPos;
  4704.         size = rect.h - (SCROLLBAR_SIZE * 2);
  4705.         DC->drawHandlePic(x, y, SCROLLBAR_SIZE, size+1, DC->Assets.scrollBar);
  4706.         y += size - 1;
  4707.         DC->drawHandlePic(x, y, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarArrowDown);
  4708.         // thumb
  4709.         thumb = Item_ListBox_ThumbDrawPosition(item);//Item_ListBox_ThumbPosition(item);
  4710.         if (thumb > y - SCROLLBAR_SIZE - 1) {
  4711.             thumb = y - SCROLLBAR_SIZE - 1;
  4712.         }
  4713.         DC->drawHandlePic(x, thumb, SCROLLBAR_SIZE, SCROLLBAR_SIZE, DC->Assets.scrollBarThumb);
  4714.  
  4715.         // adjust size for item painting
  4716.         size = rect.h - 2;
  4717.         if (listPtr->elementStyle == LISTBOX_IMAGE) {
  4718.             // fit = 0;
  4719.             x = rect.x + 1;
  4720.             y = rect.y + 1;
  4721.             for (i = listPtr->startPos; i < count; i++) {
  4722.                 // always draw at least one
  4723.                 // which may overdraw the box if it is too small for the element
  4724.                 image = DC->feederItemImage(item->special, i);
  4725.                 if (image) {
  4726.                     DC->drawHandlePic(x+1, y+1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image);
  4727.                 }
  4728.  
  4729.                 if ( item->type == ITEM_TYPE_COMBOBOX )
  4730.                 {
  4731.                     if ( i == listPtr->cursorPos )
  4732.                     {
  4733.                         DC->drawRect(x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.outlineColor);
  4734.                     }
  4735.                 }
  4736.                 else if (i == item->cursorPos) 
  4737.                 {
  4738.                     DC->drawRect(x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, item->window.borderSize, item->window.outlineColor);
  4739.                 }
  4740.  
  4741.                 listPtr->endPos++;
  4742.                 size -= listPtr->elementWidth;
  4743.                 if (size < listPtr->elementHeight) {
  4744.                     listPtr->drawPadding = listPtr->elementHeight - size;
  4745.                     break;
  4746.                 }
  4747.                 y += listPtr->elementHeight;
  4748.                 // fit++;
  4749.             }
  4750.         } else {
  4751.             
  4752.             x = rect.x + 1;
  4753.             y = rect.y + 1;
  4754.             
  4755.             for (i = listPtr->startPos; i < count; i++) 
  4756.             {
  4757.                 // always draw at least one
  4758.                 // which may overdraw the box if it is too small for the element
  4759.  
  4760.                 if ( item->type == ITEM_TYPE_COMBOBOX )
  4761.                 {
  4762.                     if ( i == listPtr->cursorPos )
  4763.                     {
  4764.                         DC->fillRect(x + 2, y + 2, rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight, item->window.outlineColor);
  4765.                     }
  4766.                 }
  4767.                 else if (i == item->cursorPos) 
  4768.                 {
  4769.                     DC->fillRect(x + 2, y + 2, rect.w - SCROLLBAR_SIZE - 4, listPtr->elementHeight, item->window.outlineColor);
  4770.                 }
  4771.  
  4772.                 if ( listPtr->numColumns > 0 ) 
  4773.                 {
  4774.                     int j;
  4775.                     for (j = 0; j < listPtr->numColumns; j++) 
  4776.                     {
  4777.                         text = DC->feederItemText(item->special, i, j, &optionalImage);
  4778.                         if (optionalImage >= 0) 
  4779.                         {
  4780.                             DC->drawHandlePic(x + 4 + listPtr->columnInfo[j].pos, y - 1 + listPtr->elementHeight / 2, listPtr->columnInfo[j].width, listPtr->columnInfo[j].width, optionalImage);
  4781.                         } 
  4782.                         else if (text) 
  4783.                         {
  4784.                             DC->drawText(x + 4 + listPtr->columnInfo[j].pos + item->textalignx, y + listPtr->elementHeight + item->textaligny, item->textFont, item->textscale, item->window.foreColor, text, listPtr->columnInfo[j].maxChars, 0 );
  4785.                         }
  4786.                     }
  4787.                 } 
  4788.                 else 
  4789.                 {
  4790.                     text = DC->feederItemText(item->special, i, 0, &optionalImage);
  4791.                     if (text) 
  4792.                     {
  4793.                         DC->drawText(x + 4, y + listPtr->elementHeight + item->textaligny, item->textFont, item->textscale, item->window.foreColor, text, 0, 0 );
  4794.                     }
  4795.                 }
  4796.  
  4797.                 listPtr->endPos++;
  4798.  
  4799.                 size -= listPtr->elementHeight;
  4800.                 if (size < listPtr->elementHeight) 
  4801.                 {
  4802.                     listPtr->drawPadding = listPtr->elementHeight - size;
  4803.                     break;
  4804.                 }
  4805.                 y += listPtr->elementHeight;
  4806.                 // fit++;
  4807.             }
  4808.         }
  4809.         // Endpos is one past the end
  4810. //        listPtr->endPos++;
  4811.     }
  4812. }
  4813.  
  4814. void Item_OwnerDraw_Paint(itemDef_t *item) 
  4815. {
  4816.     menuDef_t    *parent;
  4817.     vec4_t        color;
  4818.     vec4_t        lowLight;
  4819.  
  4820.     if (item == NULL) 
  4821.     {
  4822.         return;
  4823.     }
  4824.   
  4825.     parent = (menuDef_t*)item->parent;
  4826.  
  4827.     if (!DC->ownerDrawItem) 
  4828.     {
  4829.         return;
  4830.     }
  4831.  
  4832.     Fade(&item->window.flags, &item->window.foreColor[3], parent->fadeClamp, &item->window.nextTime, parent->fadeCycle, qtrue, parent->fadeAmount);
  4833.     
  4834.     memcpy(&color, &item->window.foreColor, sizeof(color));
  4835.     
  4836.     if (item->numColors > 0 && DC->getValue) 
  4837.     {
  4838.         // if the value is within one of the ranges then set color to that, otherwise leave at default
  4839.         int i;
  4840.         float f = DC->getValue(item->window.ownerDraw);
  4841.     
  4842.         for (i = 0; i < item->numColors; i++) 
  4843.         {
  4844.             if (f >= item->colorRanges[i].low && f <= item->colorRanges[i].high) 
  4845.             {
  4846.                 memcpy(&color, &item->colorRanges[i].color, sizeof(color));
  4847.                 break;
  4848.             }
  4849.         }
  4850.     }
  4851.  
  4852.     if (item->textStyle == ITEM_TEXTSTYLE_BLINK && !((DC->realTime/BLINK_DIVISOR) & 1)) 
  4853.     {
  4854.         lowLight[0] = 0.8 * item->window.foreColor[0]; 
  4855.         lowLight[1] = 0.8 * item->window.foreColor[1]; 
  4856.         lowLight[2] = 0.8 * item->window.foreColor[2]; 
  4857.         lowLight[3] = 0.8 * item->window.foreColor[3]; 
  4858.         LerpColor(item->window.foreColor,lowLight,color,0.5+0.5*sin(DC->realTime / PULSE_DIVISOR));
  4859.     }
  4860.  
  4861.     if ( item->window.flags & WINDOW_DISABLED )
  4862.     {
  4863.         memcpy(color, parent->disableColor, sizeof(vec4_t)); // bk001207 - FIXME: Com_Memcpy
  4864.     }
  4865.     else if (item->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(item, CVAR_ENABLE)) 
  4866.     {
  4867.         memcpy(color, parent->disableColor, sizeof(vec4_t)); // bk001207 - FIXME: Com_Memcpy
  4868.     }
  4869.     
  4870.     if (item->text) 
  4871.     {
  4872.         Item_Text_Paint(item);
  4873.  
  4874.         if (item->text[0]) 
  4875.         {
  4876.             // +8 is an offset kludge to properly align owner draw items that have text combined with them
  4877.             DC->ownerDrawItem(item->textRect.x + item->textRect.w + 8, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textFont, item->textscale, color, item->window.background, item->textStyle, item->window.ownerDrawParam );
  4878.         } 
  4879.         else 
  4880.         {
  4881.             DC->ownerDrawItem(item->textRect.x + item->textRect.w, item->window.rect.y, item->window.rect.w, item->window.rect.h, 0, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textFont, item->textscale, color, item->window.background, item->textStyle, item->window.ownerDrawParam );
  4882.         }
  4883.     } 
  4884.     else 
  4885.     {
  4886.         DC->ownerDrawItem(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, item->textalignx, item->textaligny, item->window.ownerDraw, item->window.ownerDrawFlags, item->alignment, item->special, item->textFont, item->textscale, color, item->window.background, item->textStyle, item->window.ownerDrawParam );
  4887.     }
  4888. }
  4889.  
  4890.  
  4891. void Item_Paint(itemDef_t *item) 
  4892. {
  4893.     vec4_t        red;
  4894.     menuDef_t *parent = (menuDef_t*)item->parent;
  4895.     int            xPos,textWidth;
  4896.     vec4_t        color = {1, 1, 1, 1};
  4897.     float        origWidth;
  4898.  
  4899.     red[0] = red[3] = 1;
  4900.     red[1] = red[2] = 0;
  4901.  
  4902.     if (item == NULL) 
  4903.     {
  4904.         return;
  4905.     }
  4906.  
  4907.     if (item->window.flags & WINDOW_MOUSEOVER)
  4908.     {
  4909.         if (item->descText)
  4910.         {
  4911.             textWidth = DC->getTextWidth (item->descText, item->textFont, (float) 0.2f, 0 );
  4912.  
  4913.             if (parent->descAlignment == ITEM_ALIGN_RIGHT)
  4914.             {
  4915.                 xPos = parent->descX - textWidth;    // Right justify
  4916.             }
  4917.             else if (parent->descAlignment == ITEM_ALIGN_CENTER)
  4918.             {
  4919.                 xPos = parent->descX - (textWidth/2);    // Center justify
  4920.             }
  4921.             else                                        // Left justify    
  4922.             {
  4923.                 xPos = parent->descX;
  4924.             }
  4925.  
  4926.             Item_TextColor(item, &color);
  4927.             DC->drawText(xPos, parent->descY, item->textFont, (float) 0.2f, parent->descColor, item->descText, 0, 0 );
  4928.         }
  4929.     }
  4930.  
  4931.     if (item->window.flags & WINDOW_ORBITING) 
  4932.     {
  4933.         if (DC->realTime > item->window.nextTime) 
  4934.         {
  4935.             float rx, ry, a, c, s, w, h;
  4936.       
  4937.             item->window.nextTime = DC->realTime + item->window.offsetTime;
  4938.             // translate
  4939.             w = item->window.rectClient.w / 2;
  4940.             h = item->window.rectClient.h / 2;
  4941.             rx = item->window.rectClient.x + w - item->window.rectEffects.x;
  4942.             ry = item->window.rectClient.y + h - item->window.rectEffects.y;
  4943.             a = 3 * M_PI / 180;
  4944.             c = cos(a);
  4945.             s = sin(a);
  4946.             item->window.rectClient.x = (rx * c - ry * s) + item->window.rectEffects.x - w;
  4947.             item->window.rectClient.y = (rx * s + ry * c) + item->window.rectEffects.y - h;
  4948.             Item_UpdatePosition(item);
  4949.         }
  4950.     }
  4951.  
  4952.  
  4953.   if (item->window.flags & WINDOW_INTRANSITION) {
  4954.     if (DC->realTime > item->window.nextTime) {
  4955.       int done = 0;
  4956.       item->window.nextTime = DC->realTime + item->window.offsetTime;
  4957.             // transition the x,y
  4958.             if (item->window.rectClient.x == item->window.rectEffects.x) {
  4959.                 done++;
  4960.             } else {
  4961.                 if (item->window.rectClient.x < item->window.rectEffects.x) {
  4962.                     item->window.rectClient.x += item->window.rectEffects2.x;
  4963.                     if (item->window.rectClient.x > item->window.rectEffects.x) {
  4964.                         item->window.rectClient.x = item->window.rectEffects.x;
  4965.                         done++;
  4966.                     }
  4967.                 } else {
  4968.                     item->window.rectClient.x -= item->window.rectEffects2.x;
  4969.                     if (item->window.rectClient.x < item->window.rectEffects.x) {
  4970.                         item->window.rectClient.x = item->window.rectEffects.x;
  4971.                         done++;
  4972.                     }
  4973.                 }
  4974.             }
  4975.             if (item->window.rectClient.y == item->window.rectEffects.y) {
  4976.                 done++;
  4977.             } else {
  4978.                 if (item->window.rectClient.y < item->window.rectEffects.y) {
  4979.                     item->window.rectClient.y += item->window.rectEffects2.y;
  4980.                     if (item->window.rectClient.y > item->window.rectEffects.y) {
  4981.                         item->window.rectClient.y = item->window.rectEffects.y;
  4982.                         done++;
  4983.                     }
  4984.                 } else {
  4985.                     item->window.rectClient.y -= item->window.rectEffects2.y;
  4986.                     if (item->window.rectClient.y < item->window.rectEffects.y) {
  4987.                         item->window.rectClient.y = item->window.rectEffects.y;
  4988.                         done++;
  4989.                     }
  4990.                 }
  4991.             }
  4992.             if (item->window.rectClient.w == item->window.rectEffects.w) {
  4993.                 done++;
  4994.             } else {
  4995.                 if (item->window.rectClient.w < item->window.rectEffects.w) {
  4996.                     item->window.rectClient.w += item->window.rectEffects2.w;
  4997.                     if (item->window.rectClient.w > item->window.rectEffects.w) {
  4998.                         item->window.rectClient.w = item->window.rectEffects.w;
  4999.                         done++;
  5000.                     }
  5001.                 } else {
  5002.                     item->window.rectClient.w -= item->window.rectEffects2.w;
  5003.                     if (item->window.rectClient.w < item->window.rectEffects.w) {
  5004.                         item->window.rectClient.w = item->window.rectEffects.w;
  5005.                         done++;
  5006.                     }
  5007.                 }
  5008.             }
  5009.             if (item->window.rectClient.h == item->window.rectEffects.h) {
  5010.                 done++;
  5011.             } else {
  5012.                 if (item->window.rectClient.h < item->window.rectEffects.h) {
  5013.                     item->window.rectClient.h += item->window.rectEffects2.h;
  5014.                     if (item->window.rectClient.h > item->window.rectEffects.h) {
  5015.                         item->window.rectClient.h = item->window.rectEffects.h;
  5016.                         done++;
  5017.                     }
  5018.                 } else {
  5019.                     item->window.rectClient.h -= item->window.rectEffects2.h;
  5020.                     if (item->window.rectClient.h < item->window.rectEffects.h) {
  5021.                         item->window.rectClient.h = item->window.rectEffects.h;
  5022.                         done++;
  5023.                     }
  5024.                 }
  5025.             }
  5026.  
  5027.       Item_UpdatePosition(item);
  5028.  
  5029.       if (done == 4) {
  5030.         item->window.flags &= ~WINDOW_INTRANSITION;
  5031.       }
  5032.  
  5033.     }
  5034.   }
  5035.  
  5036.     if (item->window.ownerDrawFlags && DC->ownerDrawVisible) 
  5037.     {
  5038.         int owner = DC->ownerDrawVisible(item->window.ownerDrawFlags, item->window.ownerDrawParam);
  5039.         if ( owner != -1 )
  5040.         {
  5041.             if (!owner) 
  5042.             {
  5043.                 item->window.flags &= ~WINDOW_VISIBLE;
  5044.             } 
  5045.             else 
  5046.             {
  5047.                 item->window.flags |= WINDOW_VISIBLE;
  5048.             }
  5049.         }
  5050.     }
  5051.  
  5052.     if ( item->window.flags & WINDOW_VISIBLE )
  5053.     {
  5054.         if (item->window.ownerDrawFlags && DC->ownerDrawDisabled)
  5055.         {
  5056.             if (!DC->ownerDrawDisabled(item->window.ownerDrawFlags, item->window.ownerDrawParam))
  5057.             {
  5058.                 item->window.flags &= ~WINDOW_DISABLED;
  5059.             }
  5060.             else
  5061.             {
  5062.                 item->window.flags |= WINDOW_DISABLED;
  5063.             }
  5064.         }
  5065.     }
  5066.  
  5067.     if (item->cvarFlags & (CVAR_SHOW | CVAR_HIDE)) 
  5068.     {
  5069.         if (!Item_EnableShowViaCvar(item, CVAR_SHOW)) 
  5070.         {
  5071.             return;
  5072.         }
  5073.     }
  5074.  
  5075.     if (!(item->window.flags & WINDOW_VISIBLE)) 
  5076.     {
  5077.         return;
  5078.     }
  5079.  
  5080.     origWidth = item->window.rect.w;
  5081.  
  5082.     // Alter the width of the window if this window is ownerwidth
  5083.     if ( item->window.ownerWidth )
  5084.     {
  5085.         float scale = DC->getValue ( item->window.ownerWidth );
  5086.  
  5087.         // Dont draw the window if the width is zero
  5088.         if ( scale == 0.0f )
  5089.         {
  5090.             return;
  5091.         }
  5092.  
  5093.         // Adjust the width by the percentage returned from getvalue
  5094.         item->window.rect.w *= scale;
  5095.     }
  5096.  
  5097.     // paint the rect first.. 
  5098.     Window_Paint(&item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle);
  5099.  
  5100.   if (debugMode) {
  5101.         vec4_t color;
  5102.         rectDef_t *r = Item_CorrectedTextRect(item);
  5103.     color[1] = color[3] = 1;
  5104.     color[0] = color[2] = 0;
  5105.     DC->drawRect(r->x, r->y, r->w, r->h, 1, color);
  5106.   }
  5107.  
  5108.   //DC->drawRect(item->window.rect.x, item->window.rect.y, item->window.rect.w, item->window.rect.h, 1, red);
  5109.  
  5110.     switch (item->type) 
  5111.     {
  5112.         case ITEM_TYPE_OWNERDRAW:
  5113.             Item_OwnerDraw_Paint(item);
  5114.             break;
  5115.     
  5116.         case ITEM_TYPE_TEXT:
  5117.         case ITEM_TYPE_BUTTON:
  5118.             Item_Text_Paint(item);
  5119.             break;
  5120.     
  5121.         case ITEM_TYPE_RADIOBUTTON:
  5122.             break;
  5123.             
  5124.         case ITEM_TYPE_CHECKBOX:
  5125.             break;
  5126.     
  5127.         case ITEM_TYPE_PASSWORDFIELD:
  5128.         case ITEM_TYPE_EDITFIELD:
  5129.         case ITEM_TYPE_NUMERICFIELD:
  5130.             Item_TextField_Paint(item);
  5131.             break;
  5132.     
  5133.         case ITEM_TYPE_COMBO:
  5134.             break;
  5135.  
  5136.         case ITEM_TYPE_COMBOBOX:
  5137.         case ITEM_TYPE_LISTBOX:
  5138.             Item_ListBox_Paint(item);
  5139.             break;
  5140.  
  5141.         case ITEM_TYPE_TEXTSCROLL:
  5142.             Item_TextScroll_Paint ( item );
  5143.             break;
  5144.  
  5145.         case ITEM_TYPE_MODEL:
  5146.             Item_Model_Paint(item);
  5147.             break;
  5148.     
  5149.         case ITEM_TYPE_YESNO:
  5150.             Item_YesNo_Paint(item);
  5151.             break;
  5152.         
  5153.         case ITEM_TYPE_MULTI:
  5154.             Item_Multi_Paint(item);
  5155.             break;
  5156.     
  5157.         case ITEM_TYPE_BIND:
  5158.             Item_Bind_Paint(item);
  5159.             break;
  5160.     
  5161.         case ITEM_TYPE_SLIDER:
  5162.             Item_Slider_Paint(item);
  5163.             break;
  5164.     
  5165.         default:
  5166.             break;
  5167.   }
  5168.  
  5169.     // Restore the original width of the window incase an owner width window
  5170.     // messed around with it
  5171.     item->window.rect.w = origWidth;
  5172. }
  5173.  
  5174. void Menu_Init(menuDef_t *menu) 
  5175. {
  5176.     memset(menu, 0, sizeof(menuDef_t));
  5177.     menu->cursorItem = -1;
  5178.     menu->fadeAmount = DC->Assets.fadeAmount;
  5179.     menu->fadeClamp = DC->Assets.fadeClamp;
  5180.     menu->fadeCycle = DC->Assets.fadeCycle;
  5181.  
  5182.     // Initialize the tooltip background color
  5183.     menu->tooltipBackColor[0] = 1;
  5184.     menu->tooltipBackColor[1] = 1;
  5185.     menu->tooltipBackColor[2] = 1;
  5186.     menu->tooltipBackColor[3] = 1;
  5187.  
  5188.     // Initialize the tooltip foreground color
  5189.     menu->tooltipForeColor[0] = 0;
  5190.     menu->tooltipForeColor[1] = 0;
  5191.     menu->tooltipForeColor[2] = 0;
  5192.     menu->tooltipForeColor[3] = 1;
  5193.  
  5194.     menu->tooltipScale = 1;
  5195.     menu->tooltipDelay = 500;
  5196.  
  5197.     Window_Init(&menu->window);
  5198. }
  5199.  
  5200. itemDef_t* Menu_GetItemByName ( menuDef_t* menu, const char* name )
  5201. {
  5202.     int i;
  5203.  
  5204.     if ( !menu )
  5205.     {
  5206.         return NULL;
  5207.     }
  5208.  
  5209.     for (i = 0; i < menu->itemCount; i++) 
  5210.     {
  5211.         if ( !Q_stricmp ( menu->items[i]->window.name, name ) )
  5212.         {
  5213.             return menu->items[i];
  5214.         }
  5215.     }
  5216.  
  5217.     return NULL;
  5218. }
  5219.  
  5220. itemDef_t *Menu_GetFocusedItem(menuDef_t *menu) {
  5221.   int i;
  5222.   if (menu) {
  5223.     for (i = 0; i < menu->itemCount; i++) {
  5224.       if (menu->items[i]->window.flags & WINDOW_HASFOCUS) {
  5225.         return menu->items[i];
  5226.       }
  5227.     }
  5228.   }
  5229.   return NULL;
  5230. }
  5231.  
  5232. menuDef_t *Menu_GetFocused() {
  5233.   int i;
  5234.   for (i = 0; i < menuCount; i++) {
  5235.     if (Menus[i].window.flags & WINDOW_HASFOCUS && Menus[i].window.flags & WINDOW_VISIBLE) {
  5236.       return &Menus[i];
  5237.     }
  5238.   }
  5239.   return NULL;
  5240. }
  5241.  
  5242. void Menu_ScrollFeeder(menuDef_t *menu, int feeder, qboolean down) {
  5243.     if (menu) {
  5244.         int i;
  5245.     for (i = 0; i < menu->itemCount; i++) {
  5246.             if (menu->items[i]->special == feeder) {
  5247.                 Item_ListBox_HandleKey(menu->items[i], (down) ? K_DOWNARROW : K_UPARROW, qtrue, qtrue);
  5248.                 return;
  5249.             }
  5250.         }
  5251.     }
  5252. }
  5253.  
  5254.  
  5255.  
  5256. void Menu_SetFeederSelection(menuDef_t *menu, int feeder, int index, const char *name) 
  5257. {
  5258.     if (menu == NULL) 
  5259.     {
  5260.         if (name == NULL) 
  5261.         {
  5262.             menu = Menu_GetFocused();
  5263.         } 
  5264.         else 
  5265.         {
  5266.             menu = Menus_FindByName(name);
  5267.         }
  5268.     }
  5269.  
  5270.     if (menu) 
  5271.     {
  5272.         int i;
  5273.  
  5274.         for (i = 0; i < menu->itemCount; i++) 
  5275.         {
  5276.             if (menu->items[i]->special == feeder) 
  5277.             {
  5278.                 if ( index == 0) 
  5279.                 {
  5280.                     listBoxDef_t *listPtr = (listBoxDef_t*)menu->items[i]->typeData;
  5281.                     listPtr->cursorPos = 0;
  5282.                     listPtr->startPos = 0;
  5283.                 }
  5284.                 menu->items[i]->cursorPos = index;
  5285.                 DC->feederSelection(menu->items[i]->special, menu->items[i]->cursorPos);
  5286.                 return;
  5287.             }
  5288.         }
  5289.     }
  5290. }
  5291.  
  5292. qboolean Menus_AnyFullScreenVisible() {
  5293.   int i;
  5294.   for (i = 0; i < menuCount; i++) {
  5295.     if (Menus[i].window.flags & WINDOW_VISIBLE && Menus[i].fullScreen) {
  5296.             return qtrue;
  5297.     }
  5298.   }
  5299.   return qfalse;
  5300. }
  5301.  
  5302. menuDef_t *Menus_ActivateByName(const char *p) 
  5303. {
  5304.     int          i;
  5305.     menuDef_t *m = NULL;
  5306.     menuDef_t *focus = Menu_GetFocused();
  5307.  
  5308.     // If we find a match for the window then save the pointer, otherwise
  5309.     // clear the focus of the window since the window we are looking 
  5310.     // for will get the focus eventually
  5311.     for (i = 0; i < menuCount; i++) 
  5312.     {
  5313.         if (Q_stricmp(Menus[i].window.name, p) == 0) 
  5314.         {
  5315.             m = &Menus[i];
  5316.         }
  5317.         else 
  5318.         {
  5319.             Menus[i].window.flags &= ~WINDOW_HASFOCUS;
  5320.         }
  5321.     }
  5322.  
  5323.     // make sure the menu was found in the list
  5324.     if ( !m )
  5325.     {
  5326.         return NULL;
  5327.     }
  5328.  
  5329.     // Adjust the menu stack if there was a window with focus already
  5330.     if (openMenuCount < MAX_OPEN_MENUS && focus != NULL ) 
  5331.     {
  5332.         int j;
  5333.  
  5334.         // make sure the menu with focus doenst get in there twice
  5335.         for ( j = 0; j < openMenuCount; j ++ )
  5336.         {
  5337.             if ( menuStack[j] == focus )
  5338.             {
  5339.                 break;
  5340.             }
  5341.         }
  5342.  
  5343.         // If the window isnt already in there somewhere then
  5344.         // add it to the end
  5345.         if ( j >= openMenuCount )
  5346.         {
  5347.             menuStack[openMenuCount++] = focus;
  5348.         }
  5349.     }
  5350.     
  5351.     // Activate the menu
  5352.     Menus_Activate(m);
  5353.         
  5354.     Display_CloseCinematics();
  5355.     
  5356.     return m;
  5357. }
  5358.  
  5359.  
  5360. void Item_Init(itemDef_t *item) {
  5361.     memset(item, 0, sizeof(itemDef_t));
  5362.     item->textscale = 1;
  5363.     Window_Init(&item->window);
  5364. }
  5365.  
  5366. void Menu_HandleMouseMove ( menuDef_t *menu, float x, float y ) 
  5367. {
  5368.     int            i;
  5369.     int            pass;
  5370.     qboolean    focusSet = qfalse;
  5371.  
  5372.     itemDef_t *overItem;
  5373.     if (menu == NULL) 
  5374.     {
  5375.         return;
  5376.     }
  5377.  
  5378.     if (!(menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) 
  5379.     {
  5380.         return;
  5381.     }
  5382.  
  5383.     if (itemCapture) 
  5384.     {
  5385.         //Item_MouseMove(itemCapture, x, y);
  5386.         return;
  5387.     }
  5388.  
  5389.     if (g_waitingForKey || g_editingField) 
  5390.     {
  5391.         return;
  5392.     }
  5393.  
  5394.     // FIXME: this is the whole issue of focus vs. mouse over.. 
  5395.     // need a better overall solution as i don't like going through everything twice
  5396.     for (pass = 0; pass < 2; pass++) 
  5397.     {
  5398.         for (i = menu->itemCount - 1; i >= 0 ; i-- ) 
  5399.         {
  5400.             // turn off focus each item
  5401.             // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
  5402.  
  5403.             if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) 
  5404.             {
  5405.                 continue;
  5406.             }
  5407.  
  5408.             if ( menu->items[i]->window.flags & WINDOW_DISABLED )
  5409.             {
  5410.                 continue;
  5411.             }
  5412.  
  5413.             // items can be enabled and disabled based on cvars
  5414.             if (menu->items[i]->cvarFlags & (CVAR_ENABLE | CVAR_DISABLE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_ENABLE)) {
  5415.                 continue;
  5416.             }
  5417.  
  5418.             if (menu->items[i]->cvarFlags & (CVAR_SHOW | CVAR_HIDE) && !Item_EnableShowViaCvar(menu->items[i], CVAR_SHOW)) {
  5419.                 continue;
  5420.             }
  5421.  
  5422.             if ( (!itemExclusive || itemExclusive == menu->items[i]) && Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) 
  5423.             {
  5424.                 if (pass == 1) 
  5425.                 {
  5426.                     overItem = menu->items[i];
  5427.                     if (overItem->type == ITEM_TYPE_TEXT && overItem->text) 
  5428.                     {
  5429.                         if (!Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) 
  5430.                         {
  5431.                             continue;
  5432.                         }
  5433.                     }
  5434.  
  5435.                     // if we are over an item
  5436.                     if (IsVisible(overItem->window.flags) && !(overItem->window.flags&WINDOW_DECORATION) ) 
  5437.                     {
  5438.                         // different one
  5439.                         Item_MouseEnter(overItem, x, y);
  5440.                         // Item_SetMouseOver(overItem, qtrue);
  5441.  
  5442.                         // if item is not a decoration see if it can take focus
  5443.                         if (!focusSet) 
  5444.                         {
  5445.                             focusSet = Item_SetFocus(overItem, x, y);
  5446.  
  5447.                             // Only need one focus item
  5448.                             i = -1;
  5449.                             continue;
  5450.                         }
  5451.                     }
  5452.                 }
  5453.                 else 
  5454.                 {
  5455.                     if ( !(menu->items[i]->window.flags & WINDOW_MOUSEOVER) ) 
  5456.                     {
  5457.                         Item_MouseEnter(menu->items[i], x, y);
  5458.                     }
  5459.                 }
  5460.             } 
  5461.             else if (menu->items[i]->window.flags & WINDOW_MOUSEOVER) 
  5462.             {
  5463.                 Item_MouseLeave(menu->items[i]);
  5464.                 Item_SetMouseOver(menu->items[i], qfalse);
  5465.             }
  5466.         }
  5467.     }
  5468. }
  5469.  
  5470. void Menu_Paint(menuDef_t *menu, qboolean forcePaint) 
  5471. {
  5472.     int i;
  5473.  
  5474.     if (menu == NULL) {
  5475.         return;
  5476.     }
  5477.  
  5478.     if (!(menu->window.flags & WINDOW_VISIBLE) &&  !forcePaint) {
  5479.         return;
  5480.     }
  5481.  
  5482. /*
  5483.     if (menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible(menu->window.ownerDrawFlags, menu->window.ownerDrawParam)) 
  5484.     {
  5485.         return;
  5486.     }
  5487. */
  5488.     
  5489.     if (forcePaint) {
  5490.         menu->window.flags |= WINDOW_FORCED;
  5491.     }
  5492.  
  5493.     // draw the background if necessary
  5494.     if (menu->fullScreen) {
  5495.         // implies a background shader
  5496.         // FIXME: make sure we have a default shader if fullscreen is set with no background
  5497.         DC->drawHandlePic( 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, menu->window.background );
  5498.     } else if (menu->window.background) {
  5499.         // this allows a background shader without being full screen
  5500.         //UI_DrawHandlePic(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, menu->backgroundShader);
  5501.     }
  5502.  
  5503.     // paint the background and or border
  5504.     Window_Paint(&menu->window, menu->fadeAmount, menu->fadeClamp, menu->fadeCycle );
  5505.  
  5506.     // Loop through all items for the menu and paint them
  5507.     for (i = 0; i < menu->itemCount; i++) 
  5508.     {
  5509.         if (!menu->items[i]->appearanceSlot)
  5510.         {
  5511.             Item_Paint(menu->items[i]);
  5512.         }
  5513.         else // Timed order of appearance
  5514.         {
  5515.             if (menu->appearanceTime < DC->realTime)    // Time to show another item
  5516.             {
  5517.                 menu->appearanceTime = DC->realTime + menu->appearanceIncrement;
  5518.                 menu->appearanceCnt++;
  5519.             }
  5520.  
  5521.             if (menu->items[i]->appearanceSlot<=menu->appearanceCnt)
  5522.             {
  5523.                 Item_Paint(menu->items[i]);
  5524.             }
  5525.         }
  5526.     }
  5527.  
  5528.     if (debugMode) {
  5529.         vec4_t color;
  5530.         color[0] = color[2] = color[3] = 1;
  5531.         color[1] = 0;
  5532.         DC->drawRect(menu->window.rect.x, menu->window.rect.y, menu->window.rect.w, menu->window.rect.h, 1, color);
  5533.     }
  5534. }
  5535.  
  5536. /*
  5537. ===============
  5538. Item_ValidateTypeData
  5539. ===============
  5540. */
  5541. void Item_ValidateTypeData(itemDef_t *item) 
  5542. {
  5543.     if (item->typeData) 
  5544.     {
  5545.         return;
  5546.     }
  5547.  
  5548.     switch ( item->type )
  5549.     {
  5550.         case ITEM_TYPE_LISTBOX:
  5551.         case ITEM_TYPE_COMBOBOX:
  5552.             item->typeData = trap_VM_LocalAlloc(sizeof(listBoxDef_t));
  5553.             memset(item->typeData, 0, sizeof(listBoxDef_t));
  5554.             break;
  5555.  
  5556.         case ITEM_TYPE_EDITFIELD:
  5557.         case ITEM_TYPE_NUMERICFIELD:
  5558.         case ITEM_TYPE_YESNO:
  5559.         case ITEM_TYPE_BIND:
  5560.         case ITEM_TYPE_SLIDER:
  5561.         case ITEM_TYPE_TEXT:
  5562.         case ITEM_TYPE_PASSWORDFIELD:
  5563.             item->typeData = trap_VM_LocalAlloc(sizeof(editFieldDef_t));
  5564.             memset(item->typeData, 0, sizeof(editFieldDef_t));
  5565.             if (item->type == ITEM_TYPE_EDITFIELD || item->type == ITEM_TYPE_PASSWORDFIELD) 
  5566.             {
  5567.                 if (!((editFieldDef_t *) item->typeData)->maxPaintChars) 
  5568.                 {
  5569.                     ((editFieldDef_t *) item->typeData)->maxPaintChars = MAX_EDITFIELD;
  5570.                 }
  5571.             }
  5572.             break;
  5573.  
  5574.         case ITEM_TYPE_MULTI:
  5575.             item->typeData = trap_VM_LocalAlloc(sizeof(multiDef_t));
  5576.             break;
  5577.  
  5578.         case ITEM_TYPE_MODEL:
  5579.             item->typeData = trap_VM_LocalAlloc(sizeof(modelDef_t));
  5580.             break;
  5581.  
  5582.         case ITEM_TYPE_TEXTSCROLL:
  5583.             item->typeData = trap_VM_LocalAlloc(sizeof(textScrollDef_t));
  5584.             break;
  5585.     }
  5586. }
  5587.  
  5588. /*
  5589. ===============
  5590. Item Hash
  5591. ===============
  5592. */
  5593.  
  5594. typedef struct itemHash_s
  5595. {
  5596.     keywordHash_t    keyword;
  5597.     qboolean        (*func)(itemDef_t *item, int handle);
  5598.  
  5599. } itemHash_t;
  5600.  
  5601. /*
  5602. ===============
  5603. Item Keyword Parse functions
  5604. ===============
  5605. */
  5606.  
  5607. // name <string>
  5608. qboolean ItemParse_name( itemDef_t *item, int handle ) {
  5609.     if (!PC_String_Parse(handle, &item->window.name)) {
  5610.         return qfalse;
  5611.     }
  5612.     return qtrue;
  5613. }
  5614.  
  5615. // name <string>
  5616. qboolean ItemParse_focusSound( itemDef_t *item, int handle ) {
  5617.     const char *temp;
  5618.     if (!PC_String_Parse(handle, &temp)) {
  5619.         return qfalse;
  5620.     }
  5621.     item->focusSound = DC->registerSound(temp);
  5622.     return qtrue;
  5623. }
  5624.  
  5625.  
  5626. // text <string>
  5627. qboolean ItemParse_text( itemDef_t *item, int handle ) {
  5628.     if (!PC_String_Parse(handle, &item->text)) {
  5629.         return qfalse;
  5630.     }
  5631.     return qtrue;
  5632. }
  5633.  
  5634. /*
  5635. ===============
  5636. ItemParse_descText 
  5637.     text <string>
  5638. ===============
  5639. */
  5640. qboolean ItemParse_descText( itemDef_t *item, int handle) 
  5641. {
  5642.  
  5643.     if (!PC_String_Parse(handle, &item->descText))
  5644.     {
  5645.         return qfalse;
  5646.     }
  5647.  
  5648.     return qtrue;
  5649.  
  5650. }
  5651.  
  5652.  
  5653. /*
  5654. ===============
  5655. ItemParse_text 
  5656.     text <string>
  5657. ===============
  5658. */
  5659. qboolean ItemParse_text2( itemDef_t *item, int handle) 
  5660. {
  5661.  
  5662.     if (!PC_String_Parse(handle, &item->text2))
  5663.     {
  5664.         return qfalse;
  5665.     }
  5666.  
  5667.     return qtrue;
  5668.  
  5669. }
  5670.  
  5671. /*
  5672. ===============
  5673. ItemParse_text2alignx 
  5674. ===============
  5675. */
  5676. qboolean ItemParse_text2alignx( itemDef_t *item, int handle) 
  5677. {
  5678.     if (!PC_Float_Parse(handle, &item->text2alignx)) 
  5679.     {
  5680.         return qfalse;
  5681.     }
  5682.     return qtrue;
  5683. }
  5684.  
  5685. /*
  5686. ===============
  5687. ItemParse_text2aligny 
  5688. ===============
  5689. */
  5690. qboolean ItemParse_text2aligny( itemDef_t *item, int handle) 
  5691. {
  5692.     if (!PC_Float_Parse(handle, &item->text2aligny)) 
  5693.     {
  5694.         return qfalse;
  5695.     }
  5696.     return qtrue;
  5697. }
  5698.  
  5699. // group <string>
  5700. qboolean ItemParse_group( itemDef_t *item, int handle ) {
  5701.     if (!PC_String_Parse(handle, &item->window.group)) {
  5702.         return qfalse;
  5703.     }
  5704.     return qtrue;
  5705. }
  5706.  
  5707. // asset_model <string>
  5708. qboolean ItemParse_asset_model( itemDef_t *item, int handle ) {
  5709.     const char *temp;
  5710.     modelDef_t *modelPtr;
  5711.     Item_ValidateTypeData(item);
  5712.     modelPtr = (modelDef_t*)item->typeData;
  5713.  
  5714.     if (!PC_String_Parse(handle, &temp)) {
  5715.         return qfalse;
  5716.     }
  5717.     item->asset = DC->registerModel(temp);
  5718.     modelPtr->angle = rand() % 360;
  5719.     return qtrue;
  5720. }
  5721.  
  5722. // asset_shader <string>
  5723. qboolean ItemParse_asset_shader( itemDef_t *item, int handle ) {
  5724.     const char *temp;
  5725.  
  5726.     if (!PC_String_Parse(handle, &temp)) {
  5727.         return qfalse;
  5728.     }
  5729.     item->asset = DC->registerShaderNoMip(temp);
  5730.     return qtrue;
  5731. }
  5732.  
  5733. // model_origin <number> <number> <number>
  5734. qboolean ItemParse_model_origin( itemDef_t *item, int handle ) {
  5735.     modelDef_t *modelPtr;
  5736.     Item_ValidateTypeData(item);
  5737.     modelPtr = (modelDef_t*)item->typeData;
  5738.  
  5739.     if (PC_Float_Parse(handle, &modelPtr->origin[0])) {
  5740.         if (PC_Float_Parse(handle, &modelPtr->origin[1])) {
  5741.             if (PC_Float_Parse(handle, &modelPtr->origin[2])) {
  5742.                 return qtrue;
  5743.             }
  5744.         }
  5745.     }
  5746.     return qfalse;
  5747. }
  5748.  
  5749. // model_fovx <number>
  5750. qboolean ItemParse_model_fovx( itemDef_t *item, int handle ) {
  5751.     modelDef_t *modelPtr;
  5752.     Item_ValidateTypeData(item);
  5753.     modelPtr = (modelDef_t*)item->typeData;
  5754.  
  5755.     if (!PC_Float_Parse(handle, &modelPtr->fov_x)) {
  5756.         return qfalse;
  5757.     }
  5758.     return qtrue;
  5759. }
  5760.  
  5761. // model_fovy <number>
  5762. qboolean ItemParse_model_fovy( itemDef_t *item, int handle ) {
  5763.     modelDef_t *modelPtr;
  5764.     Item_ValidateTypeData(item);
  5765.     modelPtr = (modelDef_t*)item->typeData;
  5766.  
  5767.     if (!PC_Float_Parse(handle, &modelPtr->fov_y)) {
  5768.         return qfalse;
  5769.     }
  5770.     return qtrue;
  5771. }
  5772.  
  5773. // model_rotation <integer>
  5774. qboolean ItemParse_model_rotation( itemDef_t *item, int handle ) {
  5775.     modelDef_t *modelPtr;
  5776.     Item_ValidateTypeData(item);
  5777.     modelPtr = (modelDef_t*)item->typeData;
  5778.  
  5779.     if (!PC_Int_Parse(handle, &modelPtr->rotationSpeed)) {
  5780.         return qfalse;
  5781.     }
  5782.     return qtrue;
  5783. }
  5784.  
  5785. // model_angle <integer>
  5786. qboolean ItemParse_model_angle( itemDef_t *item, int handle ) {
  5787.     modelDef_t *modelPtr;
  5788.     Item_ValidateTypeData(item);
  5789.     modelPtr = (modelDef_t*)item->typeData;
  5790.  
  5791.     if (!PC_Int_Parse(handle, &modelPtr->angle)) {
  5792.         return qfalse;
  5793.     }
  5794.     return qtrue;
  5795. }
  5796.  
  5797. // rect <rectangle>
  5798. qboolean ItemParse_rect( itemDef_t *item, int handle ) {
  5799.     if (!PC_Rect_Parse(handle, &item->window.rectClient)) {
  5800.         return qfalse;
  5801.     }
  5802.     return qtrue;
  5803. }
  5804.  
  5805. /*
  5806. ===============
  5807. ItemParse_flag
  5808.     style <integer>
  5809. ===============
  5810. */
  5811. qboolean ItemParse_flag( itemDef_t *item, int handle) 
  5812. {
  5813.     int        i;
  5814.     const char    *tempStr;
  5815.  
  5816.     if (!PC_String_Parse(handle, &tempStr))
  5817.     {
  5818.         return qfalse;
  5819.     }
  5820.  
  5821.     i=0;
  5822.     while (styles[i])
  5823.     {
  5824.         if (Q_stricmp(tempStr,itemFlags[i].string)==0)
  5825.         {
  5826.             item->window.flags |= itemFlags[i].value;
  5827.             break;
  5828.         }
  5829.         i++;
  5830.     }
  5831.  
  5832.     if (itemFlags[i].string == NULL)
  5833.     {
  5834.         Com_Printf(va(S_COLOR_YELLOW "Unknown item style value '%s'",tempStr));
  5835.     }
  5836.  
  5837.     return qtrue;
  5838. }
  5839.  
  5840. /*
  5841. ===============
  5842. ItemParse_style 
  5843.     style <integer>
  5844. ===============
  5845. */
  5846. qboolean ItemParse_style( itemDef_t *item, int handle) 
  5847. {
  5848.     if (!PC_Int_Parse(handle, &item->window.style))
  5849.     {
  5850.         Com_Printf(S_COLOR_YELLOW "Unknown item style value");
  5851.         return qfalse;
  5852.     }
  5853.  
  5854.     return qtrue;
  5855. }
  5856.  
  5857.  
  5858. // decoration
  5859. qboolean ItemParse_decoration( itemDef_t *item, int handle ) {
  5860.     item->window.flags |= WINDOW_DECORATION;
  5861.     return qtrue;
  5862. }
  5863.  
  5864. // notselectable
  5865. qboolean ItemParse_notselectable( itemDef_t *item, int handle ) {
  5866.     listBoxDef_t *listPtr;
  5867.     Item_ValidateTypeData(item);
  5868.     listPtr = (listBoxDef_t*)item->typeData;
  5869.     if (item->type == ITEM_TYPE_LISTBOX && listPtr) {
  5870.         listPtr->notselectable = qtrue;
  5871.     }
  5872.     return qtrue;
  5873. }
  5874.  
  5875. // manually wrapped
  5876. qboolean ItemParse_wrapped( itemDef_t *item, int handle ) {
  5877.     item->window.flags |= WINDOW_WRAPPED;
  5878.     return qtrue;
  5879. }
  5880.  
  5881. // auto wrapped
  5882. qboolean ItemParse_autowrapped( itemDef_t *item, int handle ) {
  5883.     item->window.flags |= WINDOW_AUTOWRAPPED;
  5884.     return qtrue;
  5885. }
  5886.  
  5887.  
  5888. // horizontalscroll
  5889. qboolean ItemParse_horizontalscroll( itemDef_t *item, int handle ) {
  5890.     item->window.flags |= WINDOW_HORIZONTAL;
  5891.     return qtrue;
  5892. }
  5893.  
  5894. /*
  5895. ===============
  5896. ItemParse_type 
  5897.     type <integer>
  5898. ===============
  5899. */
  5900. qboolean ItemParse_type( itemDef_t *item, int handle  ) 
  5901. {
  5902. //    int        i,holdInt;
  5903.  
  5904.     if (!PC_Int_Parse(handle, &item->type)) 
  5905.     {
  5906.         return qfalse;
  5907.     }
  5908.     Item_ValidateTypeData(item);
  5909.     return qtrue;
  5910. }
  5911.  
  5912. // elementwidth, used for listbox image elements
  5913. // uses textalignx for storage
  5914. qboolean ItemParse_elementwidth( itemDef_t *item, int handle ) {
  5915.     listBoxDef_t *listPtr;
  5916.  
  5917.     Item_ValidateTypeData(item);
  5918.     listPtr = (listBoxDef_t*)item->typeData;
  5919.     if (!PC_Float_Parse(handle, &listPtr->elementWidth)) {
  5920.         return qfalse;
  5921.     }
  5922.     return qtrue;
  5923. }
  5924.  
  5925. // elementheight, used for listbox image elements
  5926. // uses textaligny for storage
  5927. qboolean ItemParse_elementheight( itemDef_t *item, int handle ) {
  5928.     listBoxDef_t *listPtr;
  5929.  
  5930.     Item_ValidateTypeData(item);
  5931.     listPtr = (listBoxDef_t*)item->typeData;
  5932.     if (!PC_Float_Parse(handle, &listPtr->elementHeight)) {
  5933.         return qfalse;
  5934.     }
  5935.     return qtrue;
  5936. }
  5937.  
  5938. // feeder <float>
  5939. qboolean ItemParse_feeder( itemDef_t *item, int handle ) {
  5940.     if (!PC_Float_Parse(handle, &item->special)) {
  5941.         return qfalse;
  5942.     }
  5943.     return qtrue;
  5944. }
  5945.  
  5946. // elementtype, used to specify what type of elements a listbox contains
  5947. // uses textstyle for storage
  5948. qboolean ItemParse_elementtype( itemDef_t *item, int handle ) {
  5949.     listBoxDef_t *listPtr;
  5950.  
  5951.     Item_ValidateTypeData(item);
  5952.     if (!item->typeData)
  5953.         return qfalse;
  5954.     listPtr = (listBoxDef_t*)item->typeData;
  5955.     if (!PC_Int_Parse(handle, &listPtr->elementStyle)) {
  5956.         return qfalse;
  5957.     }
  5958.     return qtrue;
  5959. }
  5960.  
  5961. // columns sets a number of columns and an x pos and width per.. 
  5962. qboolean ItemParse_columns( itemDef_t *item, int handle ) {
  5963.     int num, i;
  5964.     listBoxDef_t *listPtr;
  5965.  
  5966.     Item_ValidateTypeData(item);
  5967.     if (!item->typeData)
  5968.         return qfalse;
  5969.     listPtr = (listBoxDef_t*)item->typeData;
  5970.     if (PC_Int_Parse(handle, &num)) {
  5971.         if (num > MAX_LB_COLUMNS) {
  5972.             num = MAX_LB_COLUMNS;
  5973.         }
  5974.         listPtr->numColumns = num;
  5975.         for (i = 0; i < num; i++) {
  5976.             int pos, width, maxChars;
  5977.  
  5978.             if (PC_Int_Parse(handle, &pos) && PC_Int_Parse(handle, &width) && PC_Int_Parse(handle, &maxChars)) {
  5979.                 listPtr->columnInfo[i].pos = pos;
  5980.                 listPtr->columnInfo[i].width = width;
  5981.                 listPtr->columnInfo[i].maxChars = maxChars;
  5982.             } else {
  5983.                 return qfalse;
  5984.             }
  5985.         }
  5986.     } else {
  5987.         return qfalse;
  5988.     }
  5989.     return qtrue;
  5990. }
  5991.  
  5992. qboolean ItemParse_border( itemDef_t *item, int handle ) {
  5993.     if (!PC_Int_Parse(handle, &item->window.border)) {
  5994.         return qfalse;
  5995.     }
  5996.     return qtrue;
  5997. }
  5998.  
  5999. qboolean ItemParse_bordersize( itemDef_t *item, int handle ) {
  6000.     if (!PC_Float_Parse(handle, &item->window.borderSize)) {
  6001.         return qfalse;
  6002.     }
  6003.     return qtrue;
  6004. }
  6005.  
  6006. qboolean ItemParse_visible( itemDef_t *item, int handle ) {
  6007.     int i;
  6008.  
  6009.     if (!PC_Int_Parse(handle, &i)) {
  6010.         return qfalse;
  6011.     }
  6012.     if (i) {
  6013.         item->window.flags |= WINDOW_VISIBLE;
  6014.     }
  6015.     return qtrue;
  6016. }
  6017.  
  6018. qboolean ItemParse_ownerdraw( itemDef_t *item, int handle ) {
  6019.     if (!PC_Int_Parse(handle, &item->window.ownerDraw)) {
  6020.         return qfalse;
  6021.     }
  6022.     item->type = ITEM_TYPE_OWNERDRAW;
  6023.     return qtrue;
  6024. }
  6025.  
  6026. qboolean ItemParse_ownerwidth( itemDef_t *item, int handle ) 
  6027. {
  6028.     if (!PC_Int_Parse(handle, &item->window.ownerWidth)) 
  6029.     {
  6030.         return qfalse;
  6031.     }
  6032.  
  6033.     return qtrue;
  6034. }
  6035.  
  6036. qboolean ItemParse_align( itemDef_t *item, int handle ) {
  6037.     if (!PC_Int_Parse(handle, &item->alignment)) {
  6038.         return qfalse;
  6039.     }
  6040.     return qtrue;
  6041. }
  6042.  
  6043. /*
  6044. ===============
  6045. ItemParse_textalign 
  6046. ===============
  6047. */
  6048. qboolean ItemParse_textalign( itemDef_t *item, int handle ) 
  6049. {
  6050.     if (!PC_Int_Parse(handle, &item->textalignment)) 
  6051.     {
  6052.         Com_Printf(S_COLOR_YELLOW "Unknown text alignment value");
  6053.         return qfalse;
  6054.     }
  6055.  
  6056.     return qtrue;
  6057.  
  6058. }
  6059.  
  6060. qboolean ItemParse_textalignx( itemDef_t *item, int handle ) {
  6061.     if (!PC_Float_Parse(handle, &item->textalignx)) {
  6062.         return qfalse;
  6063.     }
  6064.     return qtrue;
  6065. }
  6066.  
  6067. qboolean ItemParse_textaligny( itemDef_t *item, int handle ) {
  6068.     if (!PC_Float_Parse(handle, &item->textaligny)) {
  6069.         return qfalse;
  6070.     }
  6071.     return qtrue;
  6072. }
  6073.  
  6074. qboolean ItemParse_textscale( itemDef_t *item, int handle ) {
  6075.     if (!PC_Float_Parse(handle, &item->textscale)) {
  6076.         return qfalse;
  6077.     }
  6078.     return qtrue;
  6079. }
  6080.  
  6081. qboolean ItemParse_textstyle( itemDef_t *item, int handle ) {
  6082.     if (!PC_Int_Parse(handle, &item->textStyle)) {
  6083.         return qfalse;
  6084.     }
  6085.     return qtrue;
  6086. }
  6087.  
  6088. qboolean ItemParse_textfont( itemDef_t *item, int handle ) 
  6089. {
  6090.     const char* fontName;
  6091.  
  6092.     if (!PC_String_Parse(handle, &fontName) )
  6093.     {
  6094.         return qfalse;
  6095.     }
  6096.  
  6097.     item->textFont = DC->registerFont ( fontName );
  6098.  
  6099.     return qtrue;
  6100. }
  6101.  
  6102. qboolean ItemParse_backcolor( itemDef_t *item, int handle ) {
  6103.     int i;
  6104.     float f;
  6105.  
  6106.     for (i = 0; i < 4; i++) {
  6107.         if (!PC_Float_Parse(handle, &f)) {
  6108.             return qfalse;
  6109.         }
  6110.         item->window.backColor[i]  = f;
  6111.     }
  6112.     return qtrue;
  6113. }
  6114.  
  6115. qboolean ItemParse_forecolor( itemDef_t *item, int handle ) {
  6116.     int i;
  6117.     float f;
  6118.  
  6119.     for (i = 0; i < 4; i++) {
  6120.         if (!PC_Float_Parse(handle, &f)) {
  6121.             return qfalse;
  6122.         }
  6123.         item->window.foreColor[i]  = f;
  6124.         item->window.flags |= WINDOW_FORECOLORSET;
  6125.     }
  6126.     return qtrue;
  6127. }
  6128.  
  6129. qboolean ItemParse_bordercolor( itemDef_t *item, int handle ) {
  6130.     int i;
  6131.     float f;
  6132.  
  6133.     for (i = 0; i < 4; i++) {
  6134.         if (!PC_Float_Parse(handle, &f)) {
  6135.             return qfalse;
  6136.         }
  6137.         item->window.borderColor[i]  = f;
  6138.     }
  6139.     return qtrue;
  6140. }
  6141.  
  6142. qboolean ItemParse_outlinecolor( itemDef_t *item, int handle ) {
  6143.     if (!PC_Color_Parse(handle, &item->window.outlineColor)){
  6144.         return qfalse;
  6145.     }
  6146.     return qtrue;
  6147. }
  6148.  
  6149. qboolean ItemParse_background( itemDef_t *item, int handle ) {
  6150.     const char *temp;
  6151.  
  6152.     if (!PC_String_Parse(handle, &temp)) {
  6153.         return qfalse;
  6154.     }
  6155.     item->window.background = DC->registerShaderNoMip(temp);
  6156.     return qtrue;
  6157. }
  6158.  
  6159. qboolean ItemParse_cinematic( itemDef_t *item, int handle ) {
  6160.     if (!PC_String_Parse(handle, &item->window.cinematicName)) {
  6161.         return qfalse;
  6162.     }
  6163.     return qtrue;
  6164. }
  6165.  
  6166. qboolean ItemParse_doubleClick( itemDef_t *item, int handle ) {
  6167.     listBoxDef_t *listPtr;
  6168.  
  6169.     Item_ValidateTypeData(item);
  6170.     if (!item->typeData) {
  6171.         return qfalse;
  6172.     }
  6173.  
  6174.     listPtr = (listBoxDef_t*)item->typeData;
  6175.  
  6176.     if (!PC_Script_Parse(handle, &listPtr->doubleClick)) {
  6177.         return qfalse;
  6178.     }
  6179.     return qtrue;
  6180. }
  6181.  
  6182. qboolean ItemParse_hotKey ( itemDef_t* item, int handle ) {
  6183.     const char *temp;
  6184.     if (!PC_String_Parse(handle, &temp)) {
  6185.         return qfalse;
  6186.     }
  6187.  
  6188.     item->hotKey = temp[0];
  6189.  
  6190.     return qtrue;
  6191. }
  6192.  
  6193. qboolean ItemParse_onFocus( itemDef_t *item, int handle ) {
  6194.     if (!PC_Script_Parse(handle, &item->onFocus)) {
  6195.         return qfalse;
  6196.     }
  6197.     return qtrue;
  6198. }
  6199.  
  6200. qboolean ItemParse_leaveFocus( itemDef_t *item, int handle ) {
  6201.     if (!PC_Script_Parse(handle, &item->leaveFocus)) {
  6202.         return qfalse;
  6203.     }
  6204.     return qtrue;
  6205. }
  6206.  
  6207. qboolean ItemParse_mouseEnter( itemDef_t *item, int handle ) {
  6208.     if (!PC_Script_Parse(handle, &item->mouseEnter)) {
  6209.         return qfalse;
  6210.     }
  6211.     return qtrue;
  6212. }
  6213.  
  6214. qboolean ItemParse_mouseExit( itemDef_t *item, int handle ) {
  6215.     if (!PC_Script_Parse(handle, &item->mouseExit)) {
  6216.         return qfalse;
  6217.     }
  6218.     return qtrue;
  6219. }
  6220.  
  6221. qboolean ItemParse_mouseEnterText( itemDef_t *item, int handle ) {
  6222.     if (!PC_Script_Parse(handle, &item->mouseEnterText)) {
  6223.         return qfalse;
  6224.     }
  6225.     return qtrue;
  6226. }
  6227.  
  6228. qboolean ItemParse_mouseExitText( itemDef_t *item, int handle ) {
  6229.     if (!PC_Script_Parse(handle, &item->mouseExitText)) {
  6230.         return qfalse;
  6231.     }
  6232.     return qtrue;
  6233. }
  6234.  
  6235. qboolean ItemParse_action( itemDef_t *item, int handle ) {
  6236.     if (!PC_Script_Parse(handle, &item->action)) {
  6237.         return qfalse;
  6238.     }
  6239.     return qtrue;
  6240. }
  6241.  
  6242. qboolean ItemParse_special( itemDef_t *item, int handle ) {
  6243.     if (!PC_Float_Parse(handle, &item->special)) {
  6244.         return qfalse;
  6245.     }
  6246.     return qtrue;
  6247. }
  6248.  
  6249. qboolean ItemParse_cvarTest( itemDef_t *item, int handle ) {
  6250.     if (!PC_String_Parse(handle, &item->cvarTest)) {
  6251.         return qfalse;
  6252.     }
  6253.     return qtrue;
  6254. }
  6255.  
  6256. qboolean ItemParse_cvar( itemDef_t *item, int handle ) {
  6257.     editFieldDef_t *editPtr;
  6258.  
  6259.     Item_ValidateTypeData(item);
  6260.     if (!PC_String_Parse(handle, &item->cvar)) {
  6261.         return qfalse;
  6262.     }
  6263.     if (item->typeData) {
  6264.         editPtr = (editFieldDef_t*)item->typeData;
  6265.         editPtr->minVal = -1;
  6266.         editPtr->maxVal = -1;
  6267.         editPtr->defVal = -1;
  6268.     }
  6269.     return qtrue;
  6270. }
  6271.  
  6272. qboolean ItemParse_maxChars( itemDef_t *item, int handle ) {
  6273.     editFieldDef_t *editPtr;
  6274.     int maxChars;
  6275.  
  6276.     Item_ValidateTypeData(item);
  6277.     if (!item->typeData)
  6278.         return qfalse;
  6279.  
  6280.     if (!PC_Int_Parse(handle, &maxChars)) {
  6281.         return qfalse;
  6282.     }
  6283.     editPtr = (editFieldDef_t*)item->typeData;
  6284.     editPtr->maxChars = maxChars;
  6285.     return qtrue;
  6286. }
  6287.  
  6288. qboolean ItemParse_maxPaintChars( itemDef_t *item, int handle ) {
  6289.     editFieldDef_t *editPtr;
  6290.     int maxChars;
  6291.  
  6292.     Item_ValidateTypeData(item);
  6293.     if (!item->typeData)
  6294.         return qfalse;
  6295.  
  6296.     if (!PC_Int_Parse(handle, &maxChars)) {
  6297.         return qfalse;
  6298.     }
  6299.     editPtr = (editFieldDef_t*)item->typeData;
  6300.     editPtr->maxPaintChars = maxChars;
  6301.     return qtrue;
  6302. }
  6303.  
  6304.  
  6305.  
  6306. qboolean ItemParse_maxLineChars( itemDef_t *item, int handle ) 
  6307. {
  6308.     textScrollDef_t *scrollPtr;
  6309.     int                maxChars;
  6310.  
  6311.     Item_ValidateTypeData(item);
  6312.     if (!item->typeData)
  6313.         return qfalse;
  6314.  
  6315.     if (!PC_Int_Parse(handle, &maxChars)) 
  6316.     {
  6317.         return qfalse;
  6318.     }
  6319.  
  6320.     scrollPtr = (textScrollDef_t*)item->typeData;
  6321.     scrollPtr->maxLineChars = maxChars;
  6322.  
  6323.     return qtrue;
  6324. }
  6325.  
  6326. qboolean ItemParse_lineHeight( itemDef_t *item, int handle ) 
  6327. {
  6328.     textScrollDef_t *scrollPtr;
  6329.     int                height;
  6330.  
  6331.     Item_ValidateTypeData(item);
  6332.     if (!item->typeData)
  6333.         return qfalse;
  6334.  
  6335.     if (!PC_Int_Parse(handle, &height)) 
  6336.     {
  6337.         return qfalse;
  6338.     }
  6339.  
  6340.     scrollPtr = (textScrollDef_t*)item->typeData;
  6341.     scrollPtr->lineHeight = height;
  6342.  
  6343.     return qtrue;
  6344. }
  6345.  
  6346. qboolean ItemParse_cvarFloat( itemDef_t *item, int handle ) {
  6347.     editFieldDef_t *editPtr;
  6348.  
  6349.     Item_ValidateTypeData(item);
  6350.     if (!item->typeData)
  6351.         return qfalse;
  6352.     editPtr = (editFieldDef_t*)item->typeData;
  6353.     if (PC_String_Parse(handle, &item->cvar) &&
  6354.         PC_Float_Parse(handle, &editPtr->defVal) &&
  6355.         PC_Float_Parse(handle, &editPtr->minVal) &&
  6356.         PC_Float_Parse(handle, &editPtr->maxVal)) {
  6357.         return qtrue;
  6358.     }
  6359.     return qfalse;
  6360. }
  6361.  
  6362. qboolean ItemParse_cvarStrList( itemDef_t *item, int handle ) {
  6363.     pc_token_t token;
  6364.     multiDef_t *multiPtr;
  6365.     int pass;
  6366.     
  6367.     Item_ValidateTypeData(item);
  6368.     if (!item->typeData)
  6369.         return qfalse;
  6370.     multiPtr = (multiDef_t*)item->typeData;
  6371.     multiPtr->count = 0;
  6372.     multiPtr->strDef = qtrue;
  6373.  
  6374.     if (!trap_PC_ReadToken(handle, &token))
  6375.         return qfalse;
  6376.     if (*token.string != '{') {
  6377.         return qfalse;
  6378.     }
  6379.  
  6380.     pass = 0;
  6381.     while ( 1 ) {
  6382.         if (!trap_PC_ReadToken(handle, &token)) {
  6383.             PC_SourceError(handle, "end of file inside menu item\n");
  6384.             return qfalse;
  6385.         }
  6386.  
  6387.         if (*token.string == '}') {
  6388.             return qtrue;
  6389.         }
  6390.  
  6391.         if (*token.string == ',' || *token.string == ';') {
  6392.             continue;
  6393.         }
  6394.  
  6395.         if (pass == 0) {
  6396.             multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
  6397.             pass = 1;
  6398.         } else {
  6399.             multiPtr->cvarStr[multiPtr->count] = String_Alloc(token.string);
  6400.             pass = 0;
  6401.             multiPtr->count++;
  6402.             if (multiPtr->count >= MAX_MULTI_CVARS) {
  6403.                 return qfalse;
  6404.             }
  6405.         }
  6406.  
  6407.     }
  6408.     return qfalse;     // bk001205 - LCC missing return value
  6409. }
  6410.  
  6411. qboolean ItemParse_cvarFloatList( itemDef_t *item, int handle ) {
  6412.     pc_token_t token;
  6413.     multiDef_t *multiPtr;
  6414.     
  6415.     Item_ValidateTypeData(item);
  6416.     if (!item->typeData)
  6417.         return qfalse;
  6418.     multiPtr = (multiDef_t*)item->typeData;
  6419.     multiPtr->count = 0;
  6420.     multiPtr->strDef = qfalse;
  6421.  
  6422.     if (!trap_PC_ReadToken(handle, &token))
  6423.         return qfalse;
  6424.     if (*token.string != '{') {
  6425.         return qfalse;
  6426.     }
  6427.  
  6428.     while ( 1 ) {
  6429.         if (!trap_PC_ReadToken(handle, &token)) {
  6430.             PC_SourceError(handle, "end of file inside menu item\n");
  6431.             return qfalse;
  6432.         }
  6433.  
  6434.         if (*token.string == '}') {
  6435.             return qtrue;
  6436.         }
  6437.  
  6438.         if (*token.string == ',' || *token.string == ';') {
  6439.             continue;
  6440.         }
  6441.  
  6442.         multiPtr->cvarList[multiPtr->count] = String_Alloc(token.string);
  6443.         if (!PC_Float_Parse(handle, &multiPtr->cvarValue[multiPtr->count])) {
  6444.             return qfalse;
  6445.         }
  6446.  
  6447.         multiPtr->count++;
  6448.         if (multiPtr->count >= MAX_MULTI_CVARS) {
  6449.             return qfalse;
  6450.         }
  6451.  
  6452.     }
  6453.     return qfalse;     // bk001205 - LCC missing return value
  6454. }
  6455.  
  6456.  
  6457.  
  6458. qboolean ItemParse_addColorRange( itemDef_t *item, int handle ) {
  6459.     colorRangeDef_t color;
  6460.  
  6461.     if (PC_Float_Parse(handle, &color.low) &&
  6462.         PC_Float_Parse(handle, &color.high) &&
  6463.         PC_Color_Parse(handle, &color.color) ) {
  6464.         if (item->numColors < MAX_COLOR_RANGES) {
  6465.             memcpy(&item->colorRanges[item->numColors], &color, sizeof(color));
  6466.             item->numColors++;
  6467.         }
  6468.         return qtrue;
  6469.     }
  6470.     return qfalse;
  6471. }
  6472.  
  6473. qboolean ItemParse_ownerdrawFlag( itemDef_t *item, int handle ) 
  6474. {
  6475.     int i;
  6476.     if (!PC_Int_Parse(handle, &i)) 
  6477.     {
  6478.         return qfalse;
  6479.     }
  6480.     item->window.ownerDrawFlags |= i;
  6481.     return qtrue;
  6482. }
  6483.  
  6484. qboolean ItemParse_ownerdrawParam ( itemDef_t* item, int handle )
  6485. {
  6486.     if ( !PC_String_Parse ( handle, &item->window.ownerDrawParam ) )
  6487.     {
  6488.         return qfalse;
  6489.     }
  6490.  
  6491.     return qtrue;
  6492. }
  6493.  
  6494. qboolean ItemParse_enableCvar( itemDef_t *item, int handle ) {
  6495.     if (PC_Script_Parse(handle, &item->enableCvar)) {
  6496.         item->cvarFlags = CVAR_ENABLE;
  6497.         return qtrue;
  6498.     }
  6499.     return qfalse;
  6500. }
  6501.  
  6502. qboolean ItemParse_disableCvar( itemDef_t *item, int handle ) {
  6503.     if (PC_Script_Parse(handle, &item->enableCvar)) {
  6504.         item->cvarFlags = CVAR_DISABLE;
  6505.         return qtrue;
  6506.     }
  6507.     return qfalse;
  6508. }
  6509.  
  6510. qboolean ItemParse_showCvar( itemDef_t *item, int handle ) {
  6511.     if (PC_Script_Parse(handle, &item->enableCvar)) {
  6512.         item->cvarFlags = CVAR_SHOW;
  6513.         return qtrue;
  6514.     }
  6515.     return qfalse;
  6516. }
  6517.  
  6518. qboolean ItemParse_hideCvar( itemDef_t *item, int handle ) {
  6519.     if (PC_Script_Parse(handle, &item->enableCvar)) {
  6520.         item->cvarFlags = CVAR_HIDE;
  6521.         return qtrue;
  6522.     }
  6523.     return qfalse;
  6524. }
  6525.  
  6526. /*
  6527. ===============
  6528. ItemParse_align 
  6529. ===============
  6530. */
  6531. qboolean ItemParse_Appearance_slot( itemDef_t *item, int handle ) 
  6532. {
  6533.     if (!PC_Int_Parse(handle, &item->appearanceSlot))
  6534.     {
  6535.         return qfalse;
  6536.     }
  6537.     return qtrue;
  6538. }
  6539.  
  6540.  
  6541. /*
  6542. ===============
  6543. ItemParse_tooltip 
  6544. ===============
  6545. */
  6546. qboolean ItemParse_tooltip ( itemDef_t *item, int handle ) 
  6547. {
  6548.     if (!PC_String_Parse(handle, &item->tooltip))
  6549.     {
  6550.         return qfalse;
  6551.     }
  6552.  
  6553.     return qtrue;
  6554. }
  6555.  
  6556. itemHash_t itemParseKeywords[] = {
  6557.     {{"action",                NULL },        ItemParse_action            },
  6558.     {{"addColorRange",        NULL },        ItemParse_addColorRange        },
  6559.     {{"align",                NULL },        ItemParse_align                },
  6560.     {{"autowrapped",        NULL },        ItemParse_autowrapped        },
  6561.     {{"appearance_slot",    NULL },        ItemParse_Appearance_slot    },
  6562.     {{"asset_model",        NULL },        ItemParse_asset_model        },
  6563.     {{"asset_shader",        NULL },        ItemParse_asset_shader        },
  6564.     {{"backcolor",            NULL },        ItemParse_backcolor            },
  6565.     {{"background",            NULL },        ItemParse_background        },
  6566.     {{"border",                NULL },        ItemParse_border            },
  6567.     {{"bordercolor",        NULL },        ItemParse_bordercolor        },
  6568.     {{"bordersize",            NULL },        ItemParse_bordersize        },
  6569.     {{"cinematic",            NULL },        ItemParse_cinematic            },
  6570.     {{"columns",            NULL },        ItemParse_columns            },
  6571.     {{"cvar",                NULL },        ItemParse_cvar                },
  6572.     {{"cvarFloat",            NULL },        ItemParse_cvarFloat            },
  6573.     {{"cvarFloatList",        NULL },        ItemParse_cvarFloatList        },
  6574.     {{"cvarStrList",        NULL },        ItemParse_cvarStrList        },
  6575.     {{"cvarTest",            NULL },        ItemParse_cvarTest            },
  6576.     {{"desctext",            NULL },        ItemParse_descText            },
  6577.     {{"decoration",            NULL },        ItemParse_decoration        },
  6578.     {{"disableCvar",        NULL },        ItemParse_disableCvar        },
  6579.     {{"doubleclick",        NULL },        ItemParse_doubleClick        },
  6580.     {{"elementheight",        NULL },        ItemParse_elementheight        },
  6581.     {{"elementtype",        NULL },        ItemParse_elementtype        },
  6582.     {{"elementwidth",        NULL },        ItemParse_elementwidth        },
  6583.     {{"enableCvar",            NULL },        ItemParse_enableCvar        },
  6584.     {{"feeder",                NULL },        ItemParse_feeder            },
  6585.     {{"flag",                NULL },        ItemParse_flag                },
  6586.     {{"focusSound",            NULL },        ItemParse_focusSound        },
  6587.     {{"forecolor",            NULL },        ItemParse_forecolor            },
  6588.     {{"group",                NULL },        ItemParse_group                },
  6589.     {{"hideCvar",            NULL },        ItemParse_hideCvar            },
  6590.     {{"horizontalscroll",    NULL },        ItemParse_horizontalscroll    },
  6591.     {{"leaveFocus",            NULL },        ItemParse_leaveFocus        },
  6592.     {{"maxChars",            NULL },        ItemParse_maxChars            },
  6593.     {{"maxPaintChars",        NULL },        ItemParse_maxPaintChars        },
  6594.     {{"model_angle",        NULL },        ItemParse_model_angle        },
  6595.     {{"model_fovx",            NULL },        ItemParse_model_fovx        },
  6596.     {{"model_fovy",            NULL },        ItemParse_model_fovy        },
  6597.     {{"model_origin",        NULL },        ItemParse_model_origin        },
  6598.     {{"model_rotation",        NULL },        ItemParse_model_rotation    },
  6599.     {{"mouseEnter",            NULL },        ItemParse_mouseEnter        },
  6600.     {{"mouseEnterText",        NULL },        ItemParse_mouseEnterText    },
  6601.     {{"mouseExit",            NULL },        ItemParse_mouseExit            },
  6602.     {{"mouseExitText",        NULL },        ItemParse_mouseExitText        },
  6603.     {{"name",                NULL },        ItemParse_name                },
  6604.     {{"notselectable",        NULL },        ItemParse_notselectable        },
  6605.     {{"onFocus",            NULL },        ItemParse_onFocus            },
  6606.     {{"outlinecolor",        NULL },        ItemParse_outlinecolor        },
  6607.     {{"ownerdraw",            NULL },        ItemParse_ownerdraw            },
  6608.     {{"ownerdrawFlag",        NULL },        ItemParse_ownerdrawFlag        },
  6609.     {{"ownerdrawParam",        NULL },        ItemParse_ownerdrawParam    },
  6610.     {{"ownerwidth",            NULL },        ItemParse_ownerwidth        },
  6611.     {{"rect",                NULL },        ItemParse_rect                },
  6612.     {{"showCvar",            NULL },        ItemParse_showCvar            },
  6613.     {{"special",            NULL },        ItemParse_special            },
  6614.     {{"style",                NULL },        ItemParse_style                },
  6615.     {{"text",                NULL },        ItemParse_text                },
  6616.     {{"textalign",            NULL },        ItemParse_textalign            },
  6617.     {{"textalignx",            NULL },        ItemParse_textalignx        },
  6618.     {{"textaligny",            NULL },        ItemParse_textaligny        },
  6619.     {{"textscale",            NULL },        ItemParse_textscale            },
  6620.     {{"textstyle",            NULL },        ItemParse_textstyle            },
  6621.     {{"textfont",            NULL },        ItemParse_textfont            },
  6622.     {{"text2",                NULL },        ItemParse_text2                },
  6623.     {{"text2alignx",        NULL },        ItemParse_text2alignx        },
  6624.     {{"text2aligny",        NULL },        ItemParse_text2aligny        },
  6625.     {{"type",                NULL },        ItemParse_type                },
  6626.     {{"visible",            NULL },        ItemParse_visible            },
  6627.     {{"wrapped",            NULL },        ItemParse_wrapped            },
  6628.     {{"tooltip",            NULL },        ItemParse_tooltip            },
  6629.     {{"hotkey",                NULL },        ItemParse_hotKey            },
  6630.     // Text scroll specific
  6631.     {{"maxLineChars",        NULL },        ItemParse_maxLineChars        },
  6632.     {{"lineHeight",            NULL },        ItemParse_lineHeight        },
  6633.  
  6634.     {{ NULL,                NULL },        NULL                        }
  6635. };
  6636.  
  6637. keywordHash_t *itemParseKeywordHash[KEYWORDHASH_SIZE];
  6638.  
  6639. /*
  6640. ===============
  6641. Item_SetupKeywordHash
  6642. ===============
  6643. */
  6644. void Item_SetupKeywordHash(void) 
  6645. {
  6646.     int i;
  6647.  
  6648.     memset(itemParseKeywordHash, 0, sizeof(itemParseKeywordHash));
  6649.     for (i = 0; itemParseKeywords[i].keyword.name; i++) 
  6650.     {
  6651.         // Initialize the keyword collision list
  6652.         itemParseKeywords[i].keyword.next = NULL;
  6653.  
  6654.         // Add the keyword
  6655.         KeywordHash_Add( itemParseKeywordHash, (keywordHash_t*)&itemParseKeywords[i]);
  6656.     }
  6657. }
  6658.  
  6659. /*
  6660. ===============
  6661. Item_Parse
  6662. ===============
  6663. */
  6664. qboolean Item_Parse(int handle, itemDef_t *item) 
  6665. {
  6666.     pc_token_t    token;
  6667.     itemHash_t*    key;
  6668.  
  6669.     if (!trap_PC_ReadToken(handle, &token))
  6670.         return qfalse;
  6671.     if (*token.string != '{') {
  6672.         return qfalse;
  6673.     }
  6674.     while ( 1 ) {
  6675.         if (!trap_PC_ReadToken(handle, &token)) {
  6676.             PC_SourceError(handle, "end of file inside menu item\n");
  6677.             return qfalse;
  6678.         }
  6679.  
  6680.         if (*token.string == '}') {
  6681.             return qtrue;
  6682.         }
  6683.  
  6684.         key = (itemHash_t*)KeywordHash_Find(itemParseKeywordHash, token.string);
  6685.         if (!key) {
  6686.             PC_SourceError(handle, "unknown menu item keyword %s", token.string);
  6687.             continue;
  6688.         }
  6689.         
  6690.         if ( !key->func(item, handle) ) {
  6691.             PC_SourceError(handle, "couldn't parse menu item keyword %s", token.string);
  6692.             return qfalse;
  6693.         }
  6694.     }
  6695.     return qfalse;     // bk001205 - LCC missing return value
  6696. }
  6697.  
  6698.  
  6699. static void Item_TextScroll_BuildLines ( itemDef_t* item )
  6700. {
  6701.     textScrollDef_t* scrollPtr = (textScrollDef_t*) item->typeData;
  6702.     int                 width;
  6703.     char*             lineStart;
  6704.     char*             lineEnd;
  6705.     float             w;
  6706.     float             cw;
  6707.  
  6708.     scrollPtr->lineCount = 0;
  6709.  
  6710.     if (!item->text || *item->text == '\0' )
  6711.     {
  6712.         return;
  6713.     }
  6714.  
  6715.     scrollPtr->lineCount = 0;
  6716.     width = scrollPtr->maxLineChars;
  6717.  
  6718.     lineStart = (char*)item->text;
  6719.  
  6720.     lineEnd   = lineStart;
  6721.     w          = 0;
  6722.  
  6723.     // Keep going as long as there are more lines
  6724.     while ( scrollPtr->lineCount < MAX_TEXTSCROLL_LINES )
  6725.     {
  6726.         // End of the road
  6727.         if ( *lineEnd == '\0')
  6728.         {
  6729.             if ( lineStart < lineEnd )
  6730.             {
  6731.                 scrollPtr->lines[ scrollPtr->lineCount++ ] = lineStart;
  6732.             }
  6733.  
  6734.             break;
  6735.         }
  6736.  
  6737.         // Force a line end if its a '\n'
  6738.         else if ( *lineEnd == '\n' )
  6739.         {
  6740.             *lineEnd = '\0';
  6741.             scrollPtr->lines[ scrollPtr->lineCount++ ] = lineStart;
  6742.             lineStart = lineEnd + 1;
  6743.             lineEnd   = lineStart;
  6744.             w = 0;
  6745.             continue;
  6746.         }
  6747.  
  6748.         // Get the current character width 
  6749.         cw = DC->getTextWidth ( va("%c", *lineEnd), item->textFont,item->textscale, 0 );
  6750.  
  6751.         // Past the end of the boundary?
  6752.         if ( w + cw > (item->window.rect.w - SCROLLBAR_SIZE - 10) )
  6753.         {
  6754.             // Past the end so backtrack to the word boundary
  6755.             while ( *lineEnd != ' ' && *lineEnd != '\t' && lineEnd > lineStart )
  6756.             {
  6757.                 lineEnd--;
  6758.             }                    
  6759.  
  6760.             *lineEnd = '\0';
  6761.             scrollPtr->lines[ scrollPtr->lineCount++ ] = lineStart;
  6762.  
  6763.             // Skip any whitespaces
  6764.             lineEnd++;
  6765.             while ( (*lineEnd == ' ' || *lineEnd == '\t') && *lineEnd )
  6766.             {
  6767.                 lineEnd++;
  6768.             }
  6769.  
  6770.             lineStart = lineEnd;
  6771.             w = 0;
  6772.         }
  6773.         else
  6774.         {
  6775.             w += cw;
  6776.             lineEnd++;
  6777.         }
  6778.     }
  6779. }
  6780.  
  6781. // Item_InitControls
  6782. // init's special control types
  6783. void Item_InitControls(itemDef_t *item) 
  6784. {
  6785.     if (item == NULL) 
  6786.     {
  6787.         return;
  6788.     }
  6789.  
  6790.     switch ( item->type )
  6791.     {
  6792.         case ITEM_TYPE_LISTBOX:
  6793.         case ITEM_TYPE_COMBOBOX:
  6794.         {
  6795.             listBoxDef_t *listPtr = (listBoxDef_t*)item->typeData;
  6796.             item->cursorPos = 0;
  6797.             if (listPtr) 
  6798.             {
  6799.                 listPtr->cursorPos = 0;
  6800.                 listPtr->startPos = 0;
  6801.                 listPtr->endPos = 0;
  6802.                 listPtr->cursorPos = 0;
  6803.             }
  6804.  
  6805.             break;
  6806.         }
  6807.     }
  6808. }
  6809.  
  6810. /*
  6811. ===============
  6812. Menu Keyword Parse functions
  6813. ===============
  6814. */
  6815.  
  6816. qboolean MenuParse_name( itemDef_t *item, int handle ) {
  6817.     menuDef_t *menu = (menuDef_t*)item;
  6818.     if (!PC_String_Parse(handle, &menu->window.name)) {
  6819.         return qfalse;
  6820.     }
  6821.     if (Q_stricmp(menu->window.name, "main") == 0) {
  6822.         // default main as having focus
  6823.         //menu->window.flags |= WINDOW_HASFOCUS;
  6824.     }
  6825.     return qtrue;
  6826. }
  6827.  
  6828. qboolean MenuParse_fullscreen( itemDef_t *item, int handle ) {
  6829.     menuDef_t *menu = (menuDef_t*)item;
  6830.     if (!PC_Int_Parse(handle, (int*) &menu->fullScreen)) { // bk001206 - cast qboolean
  6831.         return qfalse;
  6832.     }
  6833.     return qtrue;
  6834. }
  6835.  
  6836. qboolean MenuParse_rect( itemDef_t *item, int handle ) {
  6837.     menuDef_t *menu = (menuDef_t*)item;
  6838.     if (!PC_Rect_Parse(handle, &menu->window.rect)) {
  6839.         return qfalse;
  6840.     }
  6841.     return qtrue;
  6842. }
  6843.  
  6844. /*
  6845. =================
  6846. MenuParse_style
  6847. =================
  6848. */
  6849. qboolean MenuParse_style( itemDef_t *item, int handle) 
  6850. {
  6851.     menuDef_t *menu = (menuDef_t*)item;
  6852.  
  6853.     if (!PC_Int_Parse(handle, &menu->window.style))
  6854.     {
  6855.         Com_Printf(S_COLOR_YELLOW "Unknown menu style value");
  6856.         return qfalse;
  6857.     }
  6858.  
  6859.     return qtrue;
  6860. }
  6861.  
  6862. qboolean MenuParse_visible( itemDef_t *item, int handle ) {
  6863.     int i;
  6864.     menuDef_t *menu = (menuDef_t*)item;
  6865.  
  6866.     if (!PC_Int_Parse(handle, &i)) {
  6867.         return qfalse;
  6868.     }
  6869.     if (i) {
  6870.         menu->window.flags |= WINDOW_VISIBLE;
  6871.     }
  6872.     return qtrue;
  6873. }
  6874.  
  6875. qboolean MenuParse_onOpen( itemDef_t *item, int handle ) {
  6876.     menuDef_t *menu = (menuDef_t*)item;
  6877.     if (!PC_Script_Parse(handle, &menu->onOpen)) {
  6878.         return qfalse;
  6879.     }
  6880.     return qtrue;
  6881. }
  6882.  
  6883. qboolean MenuParse_onClose( itemDef_t *item, int handle ) {
  6884.     menuDef_t *menu = (menuDef_t*)item;
  6885.     if (!PC_Script_Parse(handle, &menu->onClose)) {
  6886.         return qfalse;
  6887.     }
  6888.     return qtrue;
  6889. }
  6890.  
  6891. qboolean MenuParse_onESC( itemDef_t *item, int handle ) {
  6892.     menuDef_t *menu = (menuDef_t*)item;
  6893.     if (!PC_Script_Parse(handle, &menu->onESC)) {
  6894.         return qfalse;
  6895.     }
  6896.     return qtrue;
  6897. }
  6898.  
  6899.  
  6900.  
  6901. qboolean MenuParse_border( itemDef_t *item, int handle ) {
  6902.     menuDef_t *menu = (menuDef_t*)item;
  6903.     if (!PC_Int_Parse(handle, &menu->window.border)) {
  6904.         return qfalse;
  6905.     }
  6906.     return qtrue;
  6907. }
  6908.  
  6909. qboolean MenuParse_borderSize( itemDef_t *item, int handle ) {
  6910.     menuDef_t *menu = (menuDef_t*)item;
  6911.     if (!PC_Float_Parse(handle, &menu->window.borderSize)) {
  6912.         return qfalse;
  6913.     }
  6914.     return qtrue;
  6915. }
  6916.  
  6917. qboolean MenuParse_backcolor( itemDef_t *item, int handle ) {
  6918.     int i;
  6919.     float f;
  6920.     menuDef_t *menu = (menuDef_t*)item;
  6921.  
  6922.     for (i = 0; i < 4; i++) {
  6923.         if (!PC_Float_Parse(handle, &f)) {
  6924.             return qfalse;
  6925.         }
  6926.         menu->window.backColor[i]  = f;
  6927.     }
  6928.     return qtrue;
  6929. }
  6930.  
  6931. /*
  6932. =================
  6933. MenuParse_descAlignment
  6934. =================
  6935. */
  6936. qboolean MenuParse_descAlignment( itemDef_t *item, int handle ) 
  6937. {
  6938.     menuDef_t *menu = (menuDef_t*)item;
  6939.  
  6940.     if (!PC_Int_Parse(handle, &menu->descAlignment)) 
  6941.     {
  6942.         Com_Printf(S_COLOR_YELLOW "Unknown desc alignment value");
  6943.         return qfalse;
  6944.     }
  6945.  
  6946.     return qtrue;
  6947. }
  6948.  
  6949. /*
  6950. =================
  6951. MenuParse_descX
  6952. =================
  6953. */
  6954. qboolean MenuParse_descX( itemDef_t *item, int handle ) 
  6955. {
  6956.     menuDef_t *menu = (menuDef_t*)item;
  6957.  
  6958.     if (!PC_Int_Parse(handle, &menu->descX))
  6959.     {
  6960.         return qfalse;
  6961.     }
  6962.     return qtrue;
  6963. }
  6964.  
  6965. /*
  6966. =================
  6967. MenuParse_descY
  6968. =================
  6969. */
  6970. qboolean MenuParse_descY( itemDef_t *item, int handle ) 
  6971. {
  6972.     menuDef_t *menu = (menuDef_t*)item;
  6973.  
  6974.     if (!PC_Int_Parse(handle, &menu->descY))
  6975.     {
  6976.         return qfalse;
  6977.     }
  6978.     return qtrue;
  6979. }
  6980. /*
  6981. =================
  6982. MenuParse_descColor
  6983. =================
  6984. */
  6985. qboolean MenuParse_descColor( itemDef_t *item, int handle) 
  6986. {
  6987.     int i;
  6988.     float f;
  6989.     menuDef_t *menu = (menuDef_t*)item;
  6990.  
  6991.     for (i = 0; i < 4; i++) 
  6992.     {
  6993.         if (!PC_Float_Parse(handle, &f)) 
  6994.         {
  6995.             return qfalse;
  6996.         }
  6997.         menu->descColor[i]  = f;
  6998.     }
  6999.     return qtrue;
  7000. }
  7001.  
  7002. qboolean MenuParse_forecolor( itemDef_t *item, int handle ) {
  7003.     int i;
  7004.     float f;
  7005.     menuDef_t *menu = (menuDef_t*)item;
  7006.  
  7007.     for (i = 0; i < 4; i++) {
  7008.         if (!PC_Float_Parse(handle, &f)) {
  7009.             return qfalse;
  7010.         }
  7011.         menu->window.foreColor[i]  = f;
  7012.         menu->window.flags |= WINDOW_FORECOLORSET;
  7013.     }
  7014.     return qtrue;
  7015. }
  7016.  
  7017. qboolean MenuParse_bordercolor( itemDef_t *item, int handle ) {
  7018.     int i;
  7019.     float f;
  7020.     menuDef_t *menu = (menuDef_t*)item;
  7021.  
  7022.     for (i = 0; i < 4; i++) {
  7023.         if (!PC_Float_Parse(handle, &f)) {
  7024.             return qfalse;
  7025.         }
  7026.         menu->window.borderColor[i]  = f;
  7027.     }
  7028.     return qtrue;
  7029. }
  7030.  
  7031. qboolean MenuParse_focuscolor( itemDef_t *item, int handle ) {
  7032.     int i;
  7033.     float f;
  7034.     menuDef_t *menu = (menuDef_t*)item;
  7035.  
  7036.     for (i = 0; i < 4; i++) {
  7037.         if (!PC_Float_Parse(handle, &f)) {
  7038.             return qfalse;
  7039.         }
  7040.         menu->focusColor[i]  = f;
  7041.     }
  7042.     return qtrue;
  7043. }
  7044.  
  7045. qboolean MenuParse_disablecolor( itemDef_t *item, int handle ) {
  7046.     int i;
  7047.     float f;
  7048.     menuDef_t *menu = (menuDef_t*)item;
  7049.     for (i = 0; i < 4; i++) {
  7050.         if (!PC_Float_Parse(handle, &f)) {
  7051.             return qfalse;
  7052.         }
  7053.         menu->disableColor[i]  = f;
  7054.     }
  7055.     return qtrue;
  7056. }
  7057.  
  7058.  
  7059. qboolean MenuParse_outlinecolor( itemDef_t *item, int handle ) {
  7060.     menuDef_t *menu = (menuDef_t*)item;
  7061.     if (!PC_Color_Parse(handle, &menu->window.outlineColor)){
  7062.         return qfalse;
  7063.     }
  7064.     return qtrue;
  7065. }
  7066.  
  7067. qboolean MenuParse_background( itemDef_t *item, int handle ) {
  7068.     const char *buff;
  7069.     menuDef_t *menu = (menuDef_t*)item;
  7070.  
  7071.     if (!PC_String_Parse(handle, &buff)) {
  7072.         return qfalse;
  7073.     }
  7074.     menu->window.background = DC->registerShaderNoMip(buff);
  7075.     return qtrue;
  7076. }
  7077.  
  7078. qboolean MenuParse_cinematic( itemDef_t *item, int handle ) {
  7079.     menuDef_t *menu = (menuDef_t*)item;
  7080.  
  7081.     if (!PC_String_Parse(handle, &menu->window.cinematicName)) {
  7082.         return qfalse;
  7083.     }
  7084.     return qtrue;
  7085. }
  7086.  
  7087. qboolean MenuParse_ownerdrawFlag( itemDef_t *item, int handle ) {
  7088.     int i;
  7089.     menuDef_t *menu = (menuDef_t*)item;
  7090.  
  7091.     if (!PC_Int_Parse(handle, &i)) {
  7092.         return qfalse;
  7093.     }
  7094.     menu->window.ownerDrawFlags |= i;
  7095.     return qtrue;
  7096. }
  7097.  
  7098. qboolean MenuParse_ownerdraw( itemDef_t *item, int handle ) {
  7099.     menuDef_t *menu = (menuDef_t*)item;
  7100.  
  7101.     if (!PC_Int_Parse(handle, &menu->window.ownerDraw)) {
  7102.         return qfalse;
  7103.     }
  7104.     return qtrue;
  7105. }
  7106.  
  7107.  
  7108. // decoration
  7109. qboolean MenuParse_popup( itemDef_t *item, int handle ) {
  7110.     menuDef_t *menu = (menuDef_t*)item;
  7111.     menu->window.flags |= WINDOW_POPUP;
  7112.     return qtrue;
  7113. }
  7114.  
  7115.  
  7116. qboolean MenuParse_outOfBounds( itemDef_t *item, int handle ) {
  7117.     menuDef_t *menu = (menuDef_t*)item;
  7118.  
  7119.     menu->window.flags |= WINDOW_OOB_CLICK;
  7120.     return qtrue;
  7121. }
  7122.  
  7123. qboolean MenuParse_soundLoop( itemDef_t *item, int handle ) {
  7124.     menuDef_t *menu = (menuDef_t*)item;
  7125.  
  7126.     if (!PC_String_Parse(handle, &menu->soundName)) {
  7127.         return qfalse;
  7128.     }
  7129.     return qtrue;
  7130. }
  7131.  
  7132. qboolean MenuParse_fadeClamp( itemDef_t *item, int handle ) {
  7133.     menuDef_t *menu = (menuDef_t*)item;
  7134.  
  7135.     if (!PC_Float_Parse(handle, &menu->fadeClamp)) {
  7136.         return qfalse;
  7137.     }
  7138.     return qtrue;
  7139. }
  7140.  
  7141. qboolean MenuParse_fadeAmount( itemDef_t *item, int handle ) {
  7142.     menuDef_t *menu = (menuDef_t*)item;
  7143.  
  7144.     if (!PC_Float_Parse(handle, &menu->fadeAmount)) {
  7145.         return qfalse;
  7146.     }
  7147.     return qtrue;
  7148. }
  7149.  
  7150.  
  7151. qboolean MenuParse_fadeCycle( itemDef_t *item, int handle ) {
  7152.     menuDef_t *menu = (menuDef_t*)item;
  7153.  
  7154.     if (!PC_Int_Parse(handle, &menu->fadeCycle)) {
  7155.         return qfalse;
  7156.     }
  7157.     return qtrue;
  7158. }
  7159.  
  7160. #define VIOLENCE_NAME    "violence_"
  7161.  
  7162.  
  7163. qboolean MenuParse_itemDef( itemDef_t *item, int handle ) 
  7164. {
  7165. #if !(CGAME)
  7166.     char    temp[64];
  7167. #endif
  7168.  
  7169.     menuDef_t *menu = (menuDef_t*)item;
  7170.     if (menu->itemCount < MAX_MENUITEMS) {
  7171.         menu->items[menu->itemCount] = trap_VM_LocalAlloc(sizeof(itemDef_t));
  7172.         Item_Init(menu->items[menu->itemCount]);
  7173.         if (!Item_Parse(handle, menu->items[menu->itemCount])) {
  7174.             return qfalse;
  7175.         }
  7176.  
  7177. #if !(CGAME)
  7178.         if (!ui_allowparental.integer && menu->items[menu->itemCount]->window.name)
  7179.         {
  7180.             strncpy(temp, menu->items[menu->itemCount]->window.name, strlen(VIOLENCE_NAME));
  7181.             temp[strlen(VIOLENCE_NAME)] = 0;
  7182.             if (Q_stricmp(temp, VIOLENCE_NAME) == 0)
  7183.             {
  7184.                 return qtrue;
  7185.             }
  7186.         }
  7187. #endif
  7188.         Item_InitControls(menu->items[menu->itemCount]);
  7189.         menu->items[menu->itemCount++]->parent = menu;
  7190.     }
  7191.     return qtrue;
  7192. }
  7193. /*
  7194. =================
  7195. MenuParse_focuscolor
  7196. =================
  7197. */
  7198. qboolean MenuParse_appearanceIncrement( itemDef_t *item, int handle ) 
  7199. {
  7200.     menuDef_t *menu = (menuDef_t*)item;
  7201.  
  7202.     if (!PC_Float_Parse(handle, &menu->appearanceIncrement))
  7203.     {
  7204.         return qfalse;
  7205.     }
  7206.     return qtrue;
  7207. }
  7208.  
  7209. /*
  7210. =================
  7211. MenuParse_tooltipforecolor
  7212. =================
  7213. */
  7214. qboolean MenuParse_tooltipforecolor ( itemDef_t *item, int handle ) 
  7215. {
  7216.     int i;
  7217.     float f;
  7218.     menuDef_t *menu = (menuDef_t*)item;
  7219.  
  7220.     for (i = 0; i < 4; i++) 
  7221.     {
  7222.         if (!PC_Float_Parse(handle, &f)) 
  7223.         {
  7224.             return qfalse;
  7225.         }
  7226.  
  7227.         menu->tooltipForeColor[i]  = f;
  7228.     }
  7229.  
  7230.     return qtrue;
  7231. }
  7232.  
  7233. /*
  7234. =================
  7235. MenuParse_tooltipbackcolor
  7236. =================
  7237. */
  7238. qboolean MenuParse_tooltipbackcolor ( itemDef_t *item, int handle ) 
  7239. {
  7240.     int i;
  7241.     float f;
  7242.     menuDef_t *menu = (menuDef_t*)item;
  7243.  
  7244.     for (i = 0; i < 4; i++) 
  7245.     {
  7246.         if (!PC_Float_Parse(handle, &f)) 
  7247.         {
  7248.             return qfalse;
  7249.         }
  7250.  
  7251.         menu->tooltipBackColor[i]  = f;
  7252.     }
  7253.  
  7254.     return qtrue;
  7255. }
  7256.  
  7257. /*
  7258. =================
  7259. MenuParse_tooltipscale
  7260. =================
  7261. */
  7262. qboolean MenuParse_tooltipscale ( itemDef_t *item, int handle ) 
  7263. {
  7264.     menuDef_t *menu = (menuDef_t*)item;
  7265.  
  7266.     if (!PC_Float_Parse(handle, &menu->tooltipScale)) 
  7267.     {
  7268.         return qfalse;
  7269.     }
  7270.  
  7271.     return qtrue;
  7272. }
  7273.  
  7274. /*
  7275. =================
  7276. MenuParse_tooltipdelay
  7277. =================
  7278. */
  7279. qboolean MenuParse_tooltipdelay ( itemDef_t *item, int handle ) 
  7280. {
  7281.     menuDef_t *menu = (menuDef_t*)item;
  7282.  
  7283.     if (!PC_Int_Parse(handle, &menu->tooltipDelay)) 
  7284.     {
  7285.         return qfalse;
  7286.     }
  7287.  
  7288.     return qtrue;
  7289. }
  7290.  
  7291. /*
  7292. =================
  7293. MenuParse_tooltipfont
  7294. =================
  7295. */
  7296. qboolean MenuParse_tooltipfont( itemDef_t *item, int handle ) 
  7297. {
  7298.     const char *fontName;
  7299.     menuDef_t  *menu = (menuDef_t*)item;
  7300.  
  7301.     if (!PC_String_Parse(handle, &fontName) )
  7302.     {
  7303.         return qfalse;
  7304.     }
  7305.  
  7306.     menu->tooltipFont = DC->registerFont ( fontName );
  7307.  
  7308.     return qtrue;
  7309. }
  7310.  
  7311.  
  7312. itemHash_t menuParseKeywords[] = 
  7313. {
  7314.     {{"appearanceIncrement"        }, MenuParse_appearanceIncrement    },
  7315.     {{"backcolor"                }, MenuParse_backcolor                },
  7316.     {{"background"                }, MenuParse_background                },
  7317.     {{"border"                    }, MenuParse_border                    },
  7318.     {{"bordercolor"                }, MenuParse_bordercolor            },
  7319.     {{"borderSize"                }, MenuParse_borderSize                },
  7320.     {{"cinematic"                }, MenuParse_cinematic                },
  7321.     {{"descAlignment"            }, MenuParse_descAlignment            },
  7322.     {{"desccolor"                }, MenuParse_descColor                },
  7323.     {{"descX"                    }, MenuParse_descX                    },
  7324.     {{"descY"                    }, MenuParse_descY                    },
  7325.     {{"disablecolor"            }, MenuParse_disablecolor            },
  7326.     {{"fadeAmount"                }, MenuParse_fadeAmount                },
  7327.     {{"fadeClamp"                }, MenuParse_fadeClamp                },
  7328.     {{"fadeCycle"                }, MenuParse_fadeCycle                },
  7329.     {{"focuscolor"                }, MenuParse_focuscolor                },
  7330.     {{"forecolor"                }, MenuParse_forecolor                },
  7331.     {{"fullscreen"                }, MenuParse_fullscreen                },
  7332.     {{"itemDef"                    }, MenuParse_itemDef                },
  7333.     {{"name"                    }, MenuParse_name                    },
  7334.     {{"onClose"                    }, MenuParse_onClose                },
  7335.     {{"onESC"                    }, MenuParse_onESC                    },
  7336.     {{"outOfBoundsClick"        }, MenuParse_outOfBounds            },
  7337.     {{"onOpen"                    }, MenuParse_onOpen                    },
  7338.     {{"outlinecolor"            }, MenuParse_outlinecolor            },
  7339.     {{"ownerdraw"                }, MenuParse_ownerdraw                },
  7340.     {{"ownerdrawFlag"            }, MenuParse_ownerdrawFlag            },
  7341.     {{"popup"                    }, MenuParse_popup                    },
  7342.     {{"rect"                    }, MenuParse_rect                    },
  7343.     {{"soundLoop"                }, MenuParse_soundLoop                },
  7344.     {{"style"                    }, MenuParse_style                    },
  7345.     {{"visible"                    }, MenuParse_visible                },
  7346.     {{"tooltipforecolor"        }, MenuParse_tooltipforecolor        },
  7347.     {{"tooltipbackcolor"        }, MenuParse_tooltipbackcolor        },
  7348.     {{"tooltipscale"            }, MenuParse_tooltipscale            },
  7349.     {{"tooltipdelay"            }, MenuParse_tooltipdelay            },
  7350.     {{"tooltipfont"                }, MenuParse_tooltipfont            },
  7351.     {{ NULL,                    }, NULL                                }
  7352. };
  7353.  
  7354. keywordHash_t *menuParseKeywordHash[KEYWORDHASH_SIZE];
  7355.  
  7356. /*
  7357. ===============
  7358. Menu_SetupKeywordHash
  7359. ===============
  7360. */
  7361. void Menu_SetupKeywordHash(void) 
  7362. {
  7363.     int i;
  7364.  
  7365.     memset(menuParseKeywordHash, 0, sizeof(menuParseKeywordHash));
  7366.     for (i = 0; menuParseKeywords[i].keyword.name; i++) 
  7367.     {
  7368.         // Initialize the collision list
  7369.         menuParseKeywords[i].keyword.next = NULL;
  7370.  
  7371.         // Add the keyword
  7372.         KeywordHash_Add(menuParseKeywordHash, (keywordHash_t*)&menuParseKeywords[i]);
  7373.     }
  7374. }
  7375.  
  7376. /*
  7377. ===============
  7378. Menu_Parse
  7379. ===============
  7380. */
  7381. qboolean Menu_Parse(int handle, menuDef_t *menu) 
  7382. {
  7383.     pc_token_t        token;
  7384.     itemHash_t*        key;
  7385.  
  7386.     if (!trap_PC_ReadToken(handle, &token))
  7387.     {
  7388.         return qfalse;
  7389.     }
  7390.     
  7391.     if (*token.string != '{') 
  7392.     {
  7393.         return qfalse;
  7394.     }
  7395.     
  7396.     while ( 1 ) 
  7397.     {
  7398.         memset(&token, 0, sizeof(pc_token_t));
  7399.  
  7400.         if (!trap_PC_ReadToken(handle, &token)) 
  7401.         {
  7402.             PC_SourceError(handle, "end of file inside menu\n");
  7403.             return qfalse;
  7404.         }
  7405.  
  7406.         if (*token.string == '}') 
  7407.         {
  7408.             return qtrue;
  7409.         }
  7410.  
  7411.         key = (itemHash_t*)KeywordHash_Find(menuParseKeywordHash, token.string);
  7412.         
  7413.         if (!key) 
  7414.         {
  7415.             PC_SourceError(handle, "unknown menu keyword %s", token.string);
  7416.             continue;
  7417.         }
  7418.         
  7419.         if ( !key->func((itemDef_t*)menu, handle) ) 
  7420.         {
  7421.             PC_SourceError(handle, "couldn't parse menu keyword %s", token.string);
  7422.             return qfalse;
  7423.         }
  7424.     }
  7425.  
  7426.     // bk001205 - LCC missing return value
  7427.     return qfalse;     
  7428. }
  7429.  
  7430. /*
  7431. ===============
  7432. Menu_New
  7433. ===============
  7434. */
  7435. void Menu_New(int handle) 
  7436. {
  7437.     menuDef_t *menu = &Menus[menuCount];
  7438.  
  7439.     if (menuCount < MAX_MENUS) 
  7440.     {
  7441.         Menu_Init(menu);
  7442.         
  7443.         if (Menu_Parse(handle, menu)) 
  7444.         {
  7445.             Menu_PostParse(menu);
  7446.             menuCount++;
  7447.         }
  7448.     }
  7449. }
  7450.  
  7451. int Menu_Count() {
  7452.     return menuCount;
  7453. }
  7454.  
  7455. void Menu_PaintAll() {
  7456.     int i;
  7457.     if (captureFunc) {
  7458.         captureFunc(captureData);
  7459.     }
  7460.  
  7461.     // Make sure the color is cleared first
  7462.     DC->setColor ( NULL );
  7463.  
  7464.     for (i = 0; i < Menu_Count(); i++) {
  7465.         Menu_Paint(&Menus[i], qfalse);
  7466.     }
  7467.  
  7468.     if ( DC->tooltipItem )
  7469.     {
  7470.         Tooltip_Paint ( DC->tooltipItem );
  7471.     }
  7472.  
  7473.     if (debugMode) {
  7474.         vec4_t v = {1, 1, 1, 1};
  7475.         DC->drawText(5, 25, DC->Assets.defaultFont, 0.5f, v, va("fps: %f", DC->FPS), 0, 0 );
  7476.         DC->drawText(5, 45, DC->Assets.defaultFont, 0.5f, v, va("x: %d  y:%d", DC->cursorx,DC->cursory), 0, 0 );
  7477.     }
  7478. }
  7479.  
  7480. void Menu_Reset() {
  7481.     menuCount = 0;
  7482. }
  7483.  
  7484. displayContextDef_t *Display_GetContext() {
  7485.     return DC;
  7486. }
  7487.  
  7488. #ifndef MISSIONPACK // bk001206
  7489. static float captureX;
  7490. static float captureY;
  7491. #endif
  7492.  
  7493. void *Display_CaptureItem(int x, int y) {
  7494.     int i;
  7495.  
  7496.     for (i = 0; i < menuCount; i++) {
  7497.         // turn off focus each item
  7498.         // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
  7499.         if (Rect_ContainsPoint(&Menus[i].window.rect, x, y)) {
  7500.             return &Menus[i];
  7501.         }
  7502.     }
  7503.     return NULL;
  7504. }
  7505.  
  7506.  
  7507. // FIXME: 
  7508. qboolean Display_MouseMove(void *p, int x, int y) {
  7509.     int i;
  7510.     menuDef_t *menu = p;
  7511.  
  7512.     if (menu == NULL) {
  7513.     menu = Menu_GetFocused();
  7514.         if (menu) {
  7515.             if (menu->window.flags & WINDOW_POPUP) {
  7516.                 Menu_HandleMouseMove(menu, x, y);
  7517.                 return qtrue;
  7518.             }
  7519.         }
  7520.         for (i = 0; i < menuCount; i++) {
  7521.             Menu_HandleMouseMove(&Menus[i], x, y);
  7522.         }
  7523.     } else {
  7524.         menu->window.rect.x += x;
  7525.         menu->window.rect.y += y;
  7526.         Menu_UpdatePosition(menu);
  7527.     }
  7528.      return qtrue;
  7529.  
  7530. }
  7531.  
  7532. int Display_CursorType(int x, int y) {
  7533.     int i;
  7534.     for (i = 0; i < menuCount; i++) {
  7535.         rectDef_t r2;
  7536.         r2.x = Menus[i].window.rect.x - 3;
  7537.         r2.y = Menus[i].window.rect.y - 3;
  7538.         r2.w = r2.h = 7;
  7539.         if (Rect_ContainsPoint(&r2, x, y)) {
  7540.             return CURSOR_SIZER;
  7541.         }
  7542.     }
  7543.     return CURSOR_ARROW;
  7544. }
  7545.  
  7546.  
  7547. void Display_HandleKey(int key, qboolean down, int x, int y) {
  7548.     menuDef_t *menu = Display_CaptureItem(x, y);
  7549.     if (menu == NULL) {  
  7550.         menu = Menu_GetFocused();
  7551.     }
  7552.     if (menu) 
  7553.     {
  7554.         Menu_HandleKey(menu, key, down );
  7555.     }
  7556. }
  7557.  
  7558. static void Window_CacheContents(windowDef_t *window) {
  7559.     if (window) {
  7560.         if (window->cinematicName) {
  7561.             int cin = DC->playCinematic(window->cinematicName, 0, 0, 0, 0);
  7562.             DC->stopCinematic(cin);
  7563.         }
  7564.     }
  7565. }
  7566.  
  7567.  
  7568. static void Item_CacheContents(itemDef_t *item) {
  7569.     if (item) {
  7570.         Window_CacheContents(&item->window);
  7571.     }
  7572.  
  7573. }
  7574.  
  7575. static void Menu_CacheContents(menuDef_t *menu) {
  7576.     if (menu) {
  7577.         int i;
  7578.         Window_CacheContents(&menu->window);
  7579.         for (i = 0; i < menu->itemCount; i++) {
  7580.             Item_CacheContents(menu->items[i]);
  7581.         }
  7582.  
  7583.         if (menu->soundName && *menu->soundName) {
  7584.             DC->registerSound(menu->soundName);
  7585.         }
  7586.     }
  7587.  
  7588. }
  7589.  
  7590. void Display_CacheAll() {
  7591.     int i;
  7592.     for (i = 0; i < menuCount; i++) {
  7593.         Menu_CacheContents(&Menus[i]);
  7594.     }
  7595. }
  7596.  
  7597.  
  7598. static qboolean Menu_OverActiveItem(menuDef_t *menu, float x, float y) {
  7599.      if (menu && menu->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED)) {
  7600.         if (Rect_ContainsPoint(&menu->window.rect, x, y)) {
  7601.             int i;
  7602.             for (i = 0; i < menu->itemCount; i++) {
  7603.                 // turn off focus each item
  7604.                 // menu->items[i].window.flags &= ~WINDOW_HASFOCUS;
  7605.  
  7606.                 if (!(menu->items[i]->window.flags & (WINDOW_VISIBLE | WINDOW_FORCED))) {
  7607.                     continue;
  7608.                 }
  7609.  
  7610.                 if (menu->items[i]->window.flags & WINDOW_DECORATION) {
  7611.                     continue;
  7612.                 }
  7613.  
  7614.                 if (Rect_ContainsPoint(&menu->items[i]->window.rect, x, y)) {
  7615.                     itemDef_t *overItem = menu->items[i];
  7616.                     if (overItem->type == ITEM_TYPE_TEXT && overItem->text) {
  7617.                         if (Rect_ContainsPoint(Item_CorrectedTextRect(overItem), x, y)) {
  7618.                             return qtrue;
  7619.                         } else {
  7620.                             continue;
  7621.                         }
  7622.                     } else {
  7623.                         return qtrue;
  7624.                     }
  7625.                 }
  7626.             }
  7627.  
  7628.         }
  7629.     }
  7630.     return qfalse;
  7631. }
  7632.  
  7633. void Tooltip_Paint ( itemDef_t *item )
  7634. {
  7635.     float        w;
  7636.     float        h;
  7637.     float        x;
  7638.     float        y;
  7639.     menuDef_t    *menu;
  7640.  
  7641.     x = DC->tooltipx;
  7642.     y = DC->tooltipy;
  7643.  
  7644.     // If the item doesnt have a tooltip then dont render one
  7645.     if ( NULL == item->tooltip )
  7646.     {
  7647.         return;
  7648.     }
  7649.  
  7650.     menu = item->parent;
  7651.  
  7652.     // Only render the tooltip if the cursor has been stopped for at 
  7653.     // at least tooltipDelay time
  7654.     if ( DC->realTime - DC->tooltiptime < menu->tooltipDelay )
  7655.         return;
  7656.  
  7657.     // TODO: Determine the width and height of the text and adjust the
  7658.     //       orientation of the tooltip to ensure it fits on the screen
  7659.  
  7660.     w = DC->getTextWidth ( item->tooltip, menu->tooltipFont, menu->tooltipScale, 0 );
  7661.     h = DC->getTextHeight ( item->tooltip, menu->tooltipFont, menu->tooltipScale, 0 );
  7662.  
  7663.     // Draw the background and border for the tooltip
  7664.     DC->fillRect( x, y, w + 6, h + 6, menu->tooltipBackColor );
  7665.     DC->drawRect( x, y, w + 6, h + 6, 1, menu->tooltipForeColor );
  7666.  
  7667.     // Draw the tooltip text
  7668.     DC->drawText( x + 3, y + 2, menu->tooltipFont, menu->tooltipScale, menu->tooltipForeColor, item->tooltip, 0, 0 );
  7669. }
  7670.